From b9f4ea29f7a9f516d9c7673b761ec89c29b68eb4 Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Mon, 2 Nov 2026 11:37:33 +0700 Subject: [PATCH] =?UTF-8?q?Actions:=20Save=20Actions=E2=80=A6=20and=20Load?= =?UTF-8?q?=20Actions=E2=80=A6=20save=20a=20set=20to=20a=20file=20and=20lo?= =?UTF-8?q?ad=20it=20back?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Squashed from #5192 onto main. --- crates/ui-egui/src/i18n/bg.tsv | 10 ++ crates/ui-egui/src/i18n/bs.tsv | 10 ++ crates/ui-egui/src/i18n/ca.tsv | 10 ++ crates/ui-egui/src/i18n/cs.tsv | 10 ++ crates/ui-egui/src/i18n/da.tsv | 10 ++ crates/ui-egui/src/i18n/de.tsv | 10 ++ crates/ui-egui/src/i18n/el.tsv | 10 ++ crates/ui-egui/src/i18n/es.tsv | 10 ++ crates/ui-egui/src/i18n/fi.tsv | 10 ++ crates/ui-egui/src/i18n/fr.tsv | 10 ++ crates/ui-egui/src/i18n/hu.tsv | 10 ++ crates/ui-egui/src/i18n/id.tsv | 10 ++ crates/ui-egui/src/i18n/it.tsv | 10 ++ crates/ui-egui/src/i18n/ja.tsv | 10 ++ crates/ui-egui/src/i18n/ka.tsv | 10 ++ crates/ui-egui/src/i18n/ko.tsv | 10 ++ crates/ui-egui/src/i18n/nl.tsv | 10 ++ crates/ui-egui/src/i18n/pl.tsv | 10 ++ crates/ui-egui/src/i18n/pt-br.tsv | 10 ++ crates/ui-egui/src/i18n/ru.tsv | 10 ++ crates/ui-egui/src/i18n/sv.tsv | 10 ++ crates/ui-egui/src/i18n/tr.tsv | 10 ++ crates/ui-egui/src/i18n/uk.tsv | 10 ++ crates/ui-egui/src/i18n/vi.tsv | 10 ++ crates/ui-egui/src/i18n/zh-hans.tsv | 10 ++ crates/ui-egui/src/i18n/zh-hant.tsv | 10 ++ crates/ui-egui/src/io/save.rs | 1 + crates/ui-egui/src/menus/run.rs | 2 + crates/ui-egui/src/menus/ui_commands.rs | 12 ++ crates/ui-egui/src/panels/actions.rs | 150 +++++++++++++++++ crates/ui-egui/src/panels/actions/files.rs | 187 +++++++++++++++++++++ crates/ui-egui/src/picks.rs | 2 + docs/mcp.md | 14 ++ docs/target-app-parity.md | 1 + docs/ui-parity.md | 1 + 35 files changed, 630 insertions(+) create mode 100644 crates/ui-egui/src/panels/actions/files.rs diff --git a/crates/ui-egui/src/i18n/bg.tsv b/crates/ui-egui/src/i18n/bg.tsv index 1d11be5f2..0be439854 100644 --- a/crates/ui-egui/src/i18n/bg.tsv +++ b/crates/ui-egui/src/i18n/bg.tsv @@ -2314,6 +2314,8 @@ font-technology Variable Променливи Plates Пластини Platform: Платформа: Play Current Selection Изпълнение на текущия избор + Save Actions… Запазване на действия… + Load Actions… Зареждане на действия… Plug-in Info Информация за приставката Plug-ins Приставки Plug-in… Приставка… @@ -4112,6 +4114,14 @@ axis Both И двете @msg no selection bounds няма граници на селекцията @msg no slice selected няма избран срез @msg no such action няма такова действие +@msg no such action set няма такъв набор от действия +@msg the action sets changed; nothing was deleted наборите от действия се промениха; нищо не беше изтрито +@msg no action set to save няма набор от действия за запазване +@msg not an action set file не е файл с набор от действия +@msg the action set file is larger than 8 MiB файлът с набор от действия е по-голям от 8 MiB +@msg the action set file holds more than 1,000 actions файлът с набор от действия съдържа повече от 1000 действия +@msg the action set file needs a later version of VectorCraft файлът с набор от действия изисква по-нова версия на VectorCraft +@msg an action in the action set file has more than 10,000 steps действие във файла с набор от действия има повече от 10 000 стъпки @msg no such anchor няма такава опорна точка @msg no such artboard няма такава работна област @msg the artboard is locked работната област е заключена diff --git a/crates/ui-egui/src/i18n/bs.tsv b/crates/ui-egui/src/i18n/bs.tsv index c7fadc7f3..9e6f412d0 100644 --- a/crates/ui-egui/src/i18n/bs.tsv +++ b/crates/ui-egui/src/i18n/bs.tsv @@ -1316,6 +1316,8 @@ lighting Light Svjetlo No actions. Press ● to record. Nema akcija. Pritisnite ● za snimanje. Outline Text Tekst u obrise Play Current Selection Reprodukuj trenutni odabir + Save Actions… Sačuvaj akcije… + Load Actions… Učitaj akcije… Reflect Horizontal Odrazi vodoravno Rotate 90° CW Rotiraj za 90° u smjeru kazaljke Set 1 Skup 1 @@ -4505,6 +4507,14 @@ imageTrace Outline Obris @msg no selection bounds nema granica odabira @msg no slice selected nije odabran isječak @msg no such action nema takve akcije +@msg no such action set nema takvog skupa akcija +@msg the action sets changed; nothing was deleted skupovi akcija su se promijenili; ništa nije izbrisano +@msg no action set to save nema skupa akcija za čuvanje +@msg not an action set file nije datoteka skupa akcija +@msg the action set file is larger than 8 MiB datoteka skupa akcija je veća od 8 MiB +@msg the action set file holds more than 1,000 actions datoteka skupa akcija sadrži više od 1.000 akcija +@msg the action set file needs a later version of VectorCraft datoteka skupa akcija zahtijeva noviju verziju programa VectorCraft +@msg an action in the action set file has more than 10,000 steps akcija u datoteci skupa akcija ima više od 10.000 koraka @msg no such anchor nema takvog sidra @msg no such artboard nema takve radne ploče @msg the artboard is locked radna ploča je zaključana diff --git a/crates/ui-egui/src/i18n/ca.tsv b/crates/ui-egui/src/i18n/ca.tsv index f4fb5a5f0..cd43c748a 100644 --- a/crates/ui-egui/src/i18n/ca.tsv +++ b/crates/ui-egui/src/i18n/ca.tsv @@ -2981,6 +2981,8 @@ digits Malayalam Malaiàlam Plates Planxes Platform: Plataforma: Play Current Selection Reprodueix la selecció actual + Save Actions… Desa les accions… + Load Actions… Carrega accions… Play: Reprodueix: Plug-in Info Informació del complement Plug-ins Complements @@ -5210,6 +5212,14 @@ digits Malayalam Malaiàlam @msg no similar objects found (rotated or reflected copies are not matched); change the Global Edit Options and try again no s’ha trobat cap objecte similar (les còpies girades o reflexades no coincideixen); canvieu les opcions d’edició global i torneu-ho a provar @msg no slice selected no hi ha cap tall seleccionat @msg no such action no existeix aquesta acció +@msg no such action set no existeix aquest conjunt d’accions +@msg the action sets changed; nothing was deleted els conjunts d’accions han canviat; no s’ha suprimit res +@msg no action set to save no hi ha cap conjunt d’accions per desar +@msg not an action set file no és un fitxer de conjunt d’accions +@msg the action set file is larger than 8 MiB el fitxer de conjunt d’accions supera els 8 MiB +@msg the action set file holds more than 1,000 actions el fitxer de conjunt d’accions conté més de 1.000 accions +@msg the action set file needs a later version of VectorCraft el fitxer de conjunt d’accions necessita una versió més recent del VectorCraft +@msg an action in the action set file has more than 10,000 steps una acció del fitxer de conjunt d’accions té més de 10.000 passos @msg no such anchor no existeix aquest punt d’ancoratge @msg no such artboard no existeix aquest tauler @msg no such document no existeix aquest document diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv index 15bcf5841..28ebe1e0e 100644 --- a/crates/ui-egui/src/i18n/cs.tsv +++ b/crates/ui-egui/src/i18n/cs.tsv @@ -1341,6 +1341,8 @@ lighting Light Světlo No actions. Press ● to record. Žádné akce. Stisknutím ● spustíte záznam. Outline Text Text převedený na křivky Play Current Selection Přehrát aktuální výběr + Save Actions… Uložit akce… + Load Actions… Načíst akce… Reflect Horizontal Zrcadlit vodorovně Rotate 90° CW Otočit o 90° po směru hodin Set 1 Sada 1 @@ -4548,6 +4550,14 @@ imageTrace Outline Obrys @msg no selection bounds výběr nemá hranice @msg no slice selected není vybrán žádný řez @msg no such action taková akce neexistuje +@msg no such action set taková sada akcí neexistuje +@msg the action sets changed; nothing was deleted sady akcí se změnily; nic nebylo odstraněno +@msg no action set to save žádná sada akcí k uložení +@msg not an action set file není to soubor sady akcí +@msg the action set file is larger than 8 MiB soubor sady akcí je větší než 8 MiB +@msg the action set file holds more than 1,000 actions soubor sady akcí obsahuje více než 1 000 akcí +@msg the action set file needs a later version of VectorCraft soubor sady akcí vyžaduje novější verzi aplikace VectorCraft +@msg an action in the action set file has more than 10,000 steps akce v souboru sady akcí má více než 10 000 kroků @msg no such anchor takový kotevní bod neexistuje @msg no such artboard taková pracovní plocha neexistuje @msg the artboard is locked pracovní plocha je zamčená diff --git a/crates/ui-egui/src/i18n/da.tsv b/crates/ui-egui/src/i18n/da.tsv index 19edb61a2..5fc310dea 100644 --- a/crates/ui-egui/src/i18n/da.tsv +++ b/crates/ui-egui/src/i18n/da.tsv @@ -1252,6 +1252,8 @@ lighting Light Lys No actions. Press ● to record. Ingen handlinger. Tryk på ● for at optage. Outline Text Tekst til konturer Play Current Selection Afspil aktuel markering + Save Actions… Gem handlinger… + Load Actions… Indlæs handlinger… Reflect Horizontal Spejl vandret Rotate 90° CW Rotér 90° med uret Set 1 Sæt 1 @@ -4221,6 +4223,14 @@ imageTrace Outline Kontur @msg no selection bounds ingen grænser for markeringen @msg no slice selected intet udsnit markeret @msg no such action ingen sådan handling +@msg no such action set intet sådant handlingssæt +@msg the action sets changed; nothing was deleted handlingssættene er ændret; intet blev slettet +@msg no action set to save intet handlingssæt at gemme +@msg not an action set file ikke en handlingssætfil +@msg the action set file is larger than 8 MiB handlingssætfilen er større end 8 MiB +@msg the action set file holds more than 1,000 actions handlingssætfilen indeholder mere end 1.000 handlinger +@msg the action set file needs a later version of VectorCraft handlingssætfilen kræver en nyere version af VectorCraft +@msg an action in the action set file has more than 10,000 steps en handling i handlingssætfilen har mere end 10.000 trin @msg no such anchor intet sådant anker @msg no such artboard intet sådant artboard @msg no such document intet sådant dokument diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv index efcea52c7..2d0cbd5c8 100644 --- a/crates/ui-egui/src/i18n/de.tsv +++ b/crates/ui-egui/src/i18n/de.tsv @@ -2331,6 +2331,8 @@ diagnostics ui Oberfläche Plates Platten Platform: Plattform: Play Current Selection Aktuelle Auswahl abspielen + Save Actions… Aktionen speichern… + Load Actions… Aktionen laden… Plug-in Info Plug-in-Informationen Plug-ins Plug-ins Plug-in… Plug-in… @@ -4156,6 +4158,14 @@ theme Appearance Erscheinungsbild @msg no selection bounds keine Auswahlbegrenzung @msg no slice selected kein Slice ausgewählt @msg no such action keine solche Aktion +@msg no such action set kein solcher Aktionssatz +@msg the action sets changed; nothing was deleted die Aktionssätze haben sich geändert; nichts wurde gelöscht +@msg no action set to save kein Aktionssatz zum Speichern +@msg not an action set file keine Aktionssatzdatei +@msg the action set file is larger than 8 MiB die Aktionssatzdatei ist größer als 8 MiB +@msg the action set file holds more than 1,000 actions die Aktionssatzdatei enthält mehr als 1.000 Aktionen +@msg the action set file needs a later version of VectorCraft die Aktionssatzdatei erfordert eine neuere Version von VectorCraft +@msg an action in the action set file has more than 10,000 steps eine Aktion in der Aktionssatzdatei hat mehr als 10.000 Schritte @msg no such anchor kein solcher Ankerpunkt @msg no such artboard keine solche Zeichenfläche @msg the artboard is locked die Zeichenfläche ist gesperrt diff --git a/crates/ui-egui/src/i18n/el.tsv b/crates/ui-egui/src/i18n/el.tsv index a44a5fc92..1a158a157 100644 --- a/crates/ui-egui/src/i18n/el.tsv +++ b/crates/ui-egui/src/i18n/el.tsv @@ -3000,6 +3000,8 @@ theme Appearance Εμφάνιση Plates Πλάκες εκτύπωσης Platform: Πλατφόρμα: Play Current Selection Αναπαραγωγή τρέχουσας επιλογής + Save Actions… Αποθήκευση ενεργειών… + Load Actions… Φόρτωση ενεργειών… Plug-in Info Πληροφορίες προσθέτου Plug-in… Πρόσθετο… Point Text Objects Αντικείμενα κειμένου σημείου @@ -4195,6 +4197,14 @@ digits Malayalam Μαλαγιάλαμ @msg no selection bounds δεν υπάρχουν όρια επιλογής @msg no slice selected δεν έχει επιλεγεί τομή @msg no such action δεν υπάρχει τέτοια ενέργεια +@msg no such action set δεν υπάρχει τέτοιο σύνολο ενεργειών +@msg the action sets changed; nothing was deleted τα σύνολα ενεργειών άλλαξαν· δεν διαγράφηκε τίποτα +@msg no action set to save δεν υπάρχει σύνολο ενεργειών για αποθήκευση +@msg not an action set file δεν είναι αρχείο συνόλου ενεργειών +@msg the action set file is larger than 8 MiB το αρχείο συνόλου ενεργειών είναι μεγαλύτερο από 8 MiB +@msg the action set file holds more than 1,000 actions το αρχείο συνόλου ενεργειών περιέχει περισσότερες από 1.000 ενέργειες +@msg the action set file needs a later version of VectorCraft το αρχείο συνόλου ενεργειών απαιτεί νεότερη έκδοση του VectorCraft +@msg an action in the action set file has more than 10,000 steps μια ενέργεια στο αρχείο συνόλου ενεργειών έχει περισσότερα από 10.000 βήματα @msg no such anchor δεν υπάρχει τέτοιο σημείο αγκύρωσης @msg no such artboard δεν υπάρχει τέτοιος πίνακας σχεδίασης @msg the artboard is locked ο πίνακας σχεδίασης είναι κλειδωμένος diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv index 7b5d4ec62..24a101891 100644 --- a/crates/ui-egui/src/i18n/es.tsv +++ b/crates/ui-egui/src/i18n/es.tsv @@ -2377,6 +2377,8 @@ font-technology Variable Variables Plates Planchas Platform: Plataforma: Play Current Selection Reproducir la selección actual + Save Actions… Guardar acciones… + Load Actions… Cargar acciones… Plug-in Info Información del plugin Plug-ins Plugins Plug-in… Plugin… @@ -4241,6 +4243,14 @@ axis Both Ambos @msg no selection bounds la selección no tiene límites @msg no slice selected no hay ningún sector seleccionado @msg no such action no existe esa acción +@msg no such action set no existe ese conjunto de acciones +@msg the action sets changed; nothing was deleted los conjuntos de acciones han cambiado; no se ha eliminado nada +@msg no action set to save no hay ningún conjunto de acciones que guardar +@msg not an action set file no es un archivo de conjunto de acciones +@msg the action set file is larger than 8 MiB el archivo de conjunto de acciones supera los 8 MiB +@msg the action set file holds more than 1,000 actions el archivo de conjunto de acciones contiene más de 1000 acciones +@msg the action set file needs a later version of VectorCraft el archivo de conjunto de acciones necesita una versión más reciente de VectorCraft +@msg an action in the action set file has more than 10,000 steps una acción del archivo de conjunto de acciones tiene más de 10 000 pasos @msg no such anchor no existe ese punto de ancla @msg no such artboard no existe esa mesa de trabajo @msg the artboard is locked la mesa de trabajo está bloqueada diff --git a/crates/ui-egui/src/i18n/fi.tsv b/crates/ui-egui/src/i18n/fi.tsv index df44342dd..222629d18 100644 --- a/crates/ui-egui/src/i18n/fi.tsv +++ b/crates/ui-egui/src/i18n/fi.tsv @@ -1315,6 +1315,8 @@ lighting Light Valo No actions. Press ● to record. Ei toimintoja. Aloita tallennus painamalla ●. Outline Text Muunna teksti ääriviivoiksi Play Current Selection Toista nykyinen valinta + Save Actions… Tallenna toiminnot… + Load Actions… Lataa toiminnot… Reflect Horizontal Peilaa vaakasuunnassa Rotate 90° CW Kierrä 90° myötäpäivään Set 1 Sarja 1 @@ -4456,6 +4458,14 @@ imageTrace Outline Ääriviiva @msg no selection bounds ei valinnan rajoja @msg no slice selected viipaletta ei ole valittu @msg no such action toimintoa ei ole +@msg no such action set toimintosarjaa ei ole +@msg the action sets changed; nothing was deleted toimintosarjat muuttuivat; mitään ei poistettu +@msg no action set to save ei tallennettavaa toimintosarjaa +@msg not an action set file ei ole toimintosarjatiedosto +@msg the action set file is larger than 8 MiB toimintosarjatiedosto on suurempi kuin 8 MiB +@msg the action set file holds more than 1,000 actions toimintosarjatiedostossa on yli 1 000 toimintoa +@msg the action set file needs a later version of VectorCraft toimintosarjatiedosto vaatii uudemman VectorCraft-version +@msg an action in the action set file has more than 10,000 steps toimintosarjatiedoston toiminnossa on yli 10 000 vaihetta @msg no such anchor ankkuria ei ole @msg no such artboard piirtoalustaa ei ole @msg the artboard is locked piirtoalusta on lukittu diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv index 0f1b25b23..1bd51a4ef 100644 --- a/crates/ui-egui/src/i18n/fr.tsv +++ b/crates/ui-egui/src/i18n/fr.tsv @@ -2369,6 +2369,8 @@ font-technology Variable Variables Plates Plaques Platform: Plateforme : Play Current Selection Exécuter la sélection actuelle + Save Actions… Enregistrer les scripts… + Load Actions… Charger des scripts… Plug-in Info Informations sur le module externe Plug-ins Modules externes Plug-in… Module externe… @@ -4231,6 +4233,14 @@ axis Both Les deux @msg no selection bounds la sélection n’a pas de limites @msg no slice selected aucune tranche sélectionnée @msg no such action script inexistant +@msg no such action set jeu de scripts inexistant +@msg the action sets changed; nothing was deleted les jeux de scripts ont changé ; rien n’a été supprimé +@msg no action set to save aucun jeu de scripts à enregistrer +@msg not an action set file ce n’est pas un fichier de jeu de scripts +@msg the action set file is larger than 8 MiB le fichier de jeu de scripts dépasse 8 Mio +@msg the action set file holds more than 1,000 actions le fichier de jeu de scripts contient plus de 1 000 scripts +@msg the action set file needs a later version of VectorCraft le fichier de jeu de scripts nécessite une version plus récente de VectorCraft +@msg an action in the action set file has more than 10,000 steps un script du fichier de jeu de scripts compte plus de 10 000 étapes @msg no such anchor point d’ancrage inexistant @msg no such artboard plan de travail inexistant @msg the artboard is locked le plan de travail est verrouillé diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv index daafaf168..d106b3fe8 100644 --- a/crates/ui-egui/src/i18n/hu.tsv +++ b/crates/ui-egui/src/i18n/hu.tsv @@ -2900,6 +2900,8 @@ diagnostics ui felület Plates Nyomólemezek Platform: Platform: Play Current Selection Kijelölt művelet lejátszása + Save Actions… Műveletek mentése… + Load Actions… Műveletek betöltése… Plug-in Info Bővítmény adatai Plug-ins Bővítmények Plug-in… Bővítmény… @@ -4911,6 +4913,14 @@ imageTrace Outline Körvonal @msg no selection bounds a kijelölésnek nincsenek határai @msg no slice selected nincs kijelölt szelet @msg no such action nincs ilyen művelet +@msg no such action set nincs ilyen műveletkészlet +@msg the action sets changed; nothing was deleted a műveletkészletek megváltoztak; semmi sem törlődött +@msg no action set to save nincs menthető műveletkészlet +@msg not an action set file nem műveletkészlet-fájl +@msg the action set file is larger than 8 MiB a műveletkészlet-fájl nagyobb 8 MiB-nál +@msg the action set file holds more than 1,000 actions a műveletkészlet-fájl több mint 1000 műveletet tartalmaz +@msg the action set file needs a later version of VectorCraft a műveletkészlet-fájlhoz a VectorCraft újabb verziója kell +@msg an action in the action set file has more than 10,000 steps a műveletkészlet-fájl egyik műveletében több mint 10 000 lépés van @msg no such anchor nincs ilyen horgonypont @msg no such artboard nincs ilyen rajztábla @msg the artboard is locked a rajztábla zárolt diff --git a/crates/ui-egui/src/i18n/id.tsv b/crates/ui-egui/src/i18n/id.tsv index 9f2e16d5b..fb60a6508 100644 --- a/crates/ui-egui/src/i18n/id.tsv +++ b/crates/ui-egui/src/i18n/id.tsv @@ -1252,6 +1252,8 @@ lighting Light Cahaya No actions. Press ● to record. Tidak ada aksi. Tekan ● untuk merekam. Outline Text Garis luar teks Play Current Selection Putar seleksi saat ini + Save Actions… Simpan tindakan… + Load Actions… Muat tindakan… Reflect Horizontal Pencerminan horizontal Rotate 90° CW Putar 90° searah jarum jam Set 1 Set 1 @@ -4221,6 +4223,14 @@ imageTrace Outline Kontur @msg no selection bounds tidak ada batas seleksi @msg no slice selected tidak ada slice yang dipilih @msg no such action tidak ada aksi seperti itu +@msg no such action set tidak ada set tindakan seperti itu +@msg the action sets changed; nothing was deleted set tindakan telah berubah; tidak ada yang dihapus +@msg no action set to save tidak ada set tindakan untuk disimpan +@msg not an action set file bukan file set tindakan +@msg the action set file is larger than 8 MiB file set tindakan lebih besar dari 8 MiB +@msg the action set file holds more than 1,000 actions file set tindakan berisi lebih dari 1.000 tindakan +@msg the action set file needs a later version of VectorCraft file set tindakan memerlukan versi VectorCraft yang lebih baru +@msg an action in the action set file has more than 10,000 steps sebuah tindakan dalam file set tindakan memiliki lebih dari 10.000 langkah @msg no such anchor tidak ada jangkar seperti itu @msg no such artboard tidak ada artboard seperti itu @msg no such document tidak ada dokumen seperti itu diff --git a/crates/ui-egui/src/i18n/it.tsv b/crates/ui-egui/src/i18n/it.tsv index 8580ea7ba..79ff0b769 100644 --- a/crates/ui-egui/src/i18n/it.tsv +++ b/crates/ui-egui/src/i18n/it.tsv @@ -2407,6 +2407,8 @@ diagnostics ui interfaccia Plates Lastre Platform: Piattaforma: Play Current Selection Esegui selezione corrente + Save Actions… Salva azioni… + Load Actions… Carica azioni… Plug-in Info Informazioni plug-in Plug-ins Plug-in Plug-in… Plug-in… @@ -4282,6 +4284,14 @@ axis Both Entrambi @msg no selection bounds nessun limite della selezione @msg no slice selected nessuna sezione selezionata @msg no such action azione inesistente +@msg no such action set set di azioni inesistente +@msg the action sets changed; nothing was deleted i set di azioni sono cambiati; non è stato eliminato nulla +@msg no action set to save nessun set di azioni da salvare +@msg not an action set file non è un file di set di azioni +@msg the action set file is larger than 8 MiB il file del set di azioni supera 8 MiB +@msg the action set file holds more than 1,000 actions il file del set di azioni contiene più di 1.000 azioni +@msg the action set file needs a later version of VectorCraft il file del set di azioni richiede una versione più recente di VectorCraft +@msg an action in the action set file has more than 10,000 steps un’azione nel file del set di azioni ha più di 10.000 passaggi @msg no such anchor punto di ancoraggio inesistente @msg no such artboard tavola da disegno inesistente @msg the artboard is locked la tavola da disegno è bloccata diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv index dc4dd3827..6bbe8348a 100644 --- a/crates/ui-egui/src/i18n/ja.tsv +++ b/crates/ui-egui/src/i18n/ja.tsv @@ -2480,6 +2480,8 @@ diagnostics ui UI Plates 版 Platform: プラットフォーム: Play Current Selection 選択項目を再生 + Save Actions… アクションを保存… + Load Actions… アクションを読み込み… Plug-in Info プラグイン情報 Plug-in… プラグイン… Points ポイント @@ -4606,6 +4608,14 @@ swatch Bright Violet ビビッドバイオレット @msg tool (a tool id) is required tool (ツール ID) を指定してください @msg unknown tool `{t}` `{t}` は不明なツールです @msg no such action 指定されたアクションが見つかりません +@msg no such action set 指定されたアクションセットが見つかりません +@msg the action sets changed; nothing was deleted アクションセットが変更されたため、何も削除しませんでした +@msg no action set to save 保存するアクションセットがありません +@msg not an action set file アクションセットファイルではありません +@msg the action set file is larger than 8 MiB アクションセットファイルが 8 MiB を超えています +@msg the action set file holds more than 1,000 actions アクションセットファイルのアクションが 1,000 個を超えています +@msg the action set file needs a later version of VectorCraft このアクションセットファイルには新しいバージョンの VectorCraft が必要です +@msg an action in the action set file has more than 10,000 steps アクションセットファイルに 10,000 ステップを超えるアクションがあります @msg choose a folder to export to 書き出し先のフォルダーを選択してください @msg the selection has no URL (or they differ) 選択したオブジェクトに URL がありません (または URL がそれぞれ異なります) @msg select some type first 先にテキストを選択してください diff --git a/crates/ui-egui/src/i18n/ka.tsv b/crates/ui-egui/src/i18n/ka.tsv index 5e13eb084..0e060cd93 100644 --- a/crates/ui-egui/src/i18n/ka.tsv +++ b/crates/ui-egui/src/i18n/ka.tsv @@ -1171,6 +1171,8 @@ lighting Light სინათლე No actions. Press ● to record. მოქმედებები არ არის. ჩასაწერად დააჭირეთ ●-ს. Outline Text ტექსტის კონტურებად გარდაქმნა Play Current Selection მიმდინარე მონიშნულის შესრულება + Save Actions… მოქმედებების შენახვა… + Load Actions… მოქმედებების ჩატვირთვა… Reflect Horizontal ჰორიზონტალურად არეკვლა Rotate 90° CW 90°-ით შემობრუნება საათის ისრის მიმართულებით Set 1 ნაკრები 1 @@ -4010,6 +4012,14 @@ font-technology Variable ცვლადი @msg no selection bounds მონიშნულის საზღვრები არ არის @msg no slice selected ნაჭერი მონიშნული არ არის @msg no such action ასეთი მოქმედება არ არის +@msg no such action set ასეთი მოქმედებების ნაკრები არ არის +@msg the action sets changed; nothing was deleted მოქმედებების ნაკრებები შეიცვალა; არაფერი წაშლილა +@msg no action set to save შესანახი მოქმედებების ნაკრები არ არის +@msg not an action set file ეს არ არის მოქმედებების ნაკრების ფაილი +@msg the action set file is larger than 8 MiB მოქმედებების ნაკრების ფაილი 8 MiB-ზე დიდია +@msg the action set file holds more than 1,000 actions მოქმედებების ნაკრების ფაილი 1000-ზე მეტ მოქმედებას შეიცავს +@msg the action set file needs a later version of VectorCraft მოქმედებების ნაკრების ფაილს VectorCraft-ის უფრო ახალი ვერსია სჭირდება +@msg an action in the action set file has more than 10,000 steps მოქმედებების ნაკრების ფაილში ერთ-ერთ მოქმედებას 10 000-ზე მეტი ნაბიჯი აქვს @msg no such anchor ასეთი საყრდენი წერტილი არ არის @msg no such artboard ასეთი სამუშაო დაფა არ არის @msg the artboard is locked სამუშაო დაფა ჩაკეტილია diff --git a/crates/ui-egui/src/i18n/ko.tsv b/crates/ui-egui/src/i18n/ko.tsv index ca5fa5c3a..7b6cccabf 100644 --- a/crates/ui-egui/src/i18n/ko.tsv +++ b/crates/ui-egui/src/i18n/ko.tsv @@ -2470,6 +2470,8 @@ diagnostics ui UI Plates 인쇄판 Platform: 플랫폼: Play Current Selection 현재 선택 항목 재생 + Save Actions… 액션 저장… + Load Actions… 액션 불러오기… Plug-in Info 플러그인 정보 Plug-in… 플러그인… Points 포인트 @@ -4533,6 +4535,14 @@ theme Appearance 외관 @msg tool (a tool id) is required 도구(도구 id)가 필요합니다 @msg unknown tool `{t}` 알 수 없는 도구 `{t}` @msg no such action 해당 동작이 없습니다 +@msg no such action set 해당 액션 세트가 없습니다 +@msg the action sets changed; nothing was deleted 액션 세트가 바뀌어 아무것도 삭제하지 않았습니다 +@msg no action set to save 저장할 액션 세트가 없습니다 +@msg not an action set file 액션 세트 파일이 아닙니다 +@msg the action set file is larger than 8 MiB 액션 세트 파일이 8 MiB보다 큽니다 +@msg the action set file holds more than 1,000 actions 액션 세트 파일의 액션이 1,000개를 넘습니다 +@msg the action set file needs a later version of VectorCraft 이 액션 세트 파일을 열려면 최신 버전의 VectorCraft가 필요합니다 +@msg an action in the action set file has more than 10,000 steps 액션 세트 파일에 단계가 10,000개를 넘는 액션이 있습니다 @msg choose a folder to export to 내보낼 폴더를 선택하세요 @msg the selection has no URL (or they differ) 선택 항목에 URL이 없거나 서로 다릅니다 @msg select some type first 먼저 문자를 선택하세요 diff --git a/crates/ui-egui/src/i18n/nl.tsv b/crates/ui-egui/src/i18n/nl.tsv index 4ff69b6a1..00090f067 100644 --- a/crates/ui-egui/src/i18n/nl.tsv +++ b/crates/ui-egui/src/i18n/nl.tsv @@ -1266,6 +1266,8 @@ lighting Light Licht No actions. Press ● to record. Geen acties. Druk op ● om op te nemen. Outline Text Tekst omlijnen Play Current Selection Huidige selectie afspelen + Save Actions… Acties opslaan… + Load Actions… Acties laden… Reflect Horizontal Horizontaal spiegelen Rotate 90° CW 90° met de klok mee draaien Set 1 Set 1 @@ -4233,6 +4235,14 @@ imageTrace Outline Contour @msg no selection bounds geen begrenzing van de selectie @msg no slice selected geen slice geselecteerd @msg no such action actie bestaat niet +@msg no such action set actieset bestaat niet +@msg the action sets changed; nothing was deleted de actiesets zijn gewijzigd; er is niets verwijderd +@msg no action set to save geen actieset om op te slaan +@msg not an action set file geen actiesetbestand +@msg the action set file is larger than 8 MiB het actiesetbestand is groter dan 8 MiB +@msg the action set file holds more than 1,000 actions het actiesetbestand bevat meer dan 1.000 acties +@msg the action set file needs a later version of VectorCraft het actiesetbestand vereist een nieuwere versie van VectorCraft +@msg an action in the action set file has more than 10,000 steps een actie in het actiesetbestand heeft meer dan 10.000 stappen @msg no such anchor anker bestaat niet @msg no such artboard tekengebied bestaat niet @msg no such document document bestaat niet diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv index 17db44fb6..5c83cc58c 100644 --- a/crates/ui-egui/src/i18n/pl.tsv +++ b/crates/ui-egui/src/i18n/pl.tsv @@ -1255,6 +1255,8 @@ lighting Light Światło No actions. Press ● to record. Brak operacji. Naciśnij ●, aby nagrać. Outline Text Kontury tekstu Play Current Selection Odtwórz bieżące zaznaczenie + Save Actions… Zapisz operacje… + Load Actions… Wczytaj operacje… Reflect Horizontal Odbij w poziomie Rotate 90° CW Obróć o 90° w prawo Set 1 Zestaw 1 @@ -4371,6 +4373,14 @@ imageTrace Outline Kontur @msg no selection bounds brak granic zaznaczenia @msg no slice selected nie zaznaczono plasterka @msg no such action brak takiej operacji +@msg no such action set brak takiego zestawu operacji +@msg the action sets changed; nothing was deleted zestawy operacji się zmieniły; nic nie usunięto +@msg no action set to save brak zestawu operacji do zapisania +@msg not an action set file to nie jest plik zestawu operacji +@msg the action set file is larger than 8 MiB plik zestawu operacji jest większy niż 8 MiB +@msg the action set file holds more than 1,000 actions plik zestawu operacji zawiera ponad 1000 operacji +@msg the action set file needs a later version of VectorCraft plik zestawu operacji wymaga nowszej wersji programu VectorCraft +@msg an action in the action set file has more than 10,000 steps operacja w pliku zestawu operacji ma ponad 10 000 kroków @msg no such anchor brak takiego punktu @msg no such artboard brak takiego obszaru kompozycji @msg the artboard is locked obszar kompozycji jest zablokowany diff --git a/crates/ui-egui/src/i18n/pt-br.tsv b/crates/ui-egui/src/i18n/pt-br.tsv index 611bad136..20d806ddd 100644 --- a/crates/ui-egui/src/i18n/pt-br.tsv +++ b/crates/ui-egui/src/i18n/pt-br.tsv @@ -1970,6 +1970,8 @@ Plates Placas Platform: Plataforma: Play Current Selection Reproduzir Seleção Atual + Save Actions… Salvar Ações… + Load Actions… Carregar Ações… Plug-in Info Informações do Plug-in Plug-ins Plug-ins Plug-in… Plug-in… @@ -3832,6 +3834,14 @@ axis Both Ambos @msg no selection bounds sem limites de seleção @msg no slice selected nenhuma fatia selecionada @msg no such action ação inexistente +@msg no such action set conjunto de ações inexistente +@msg the action sets changed; nothing was deleted os conjuntos de ações mudaram; nada foi excluído +@msg no action set to save nenhum conjunto de ações para salvar +@msg not an action set file não é um arquivo de conjunto de ações +@msg the action set file is larger than 8 MiB o arquivo de conjunto de ações tem mais de 8 MiB +@msg the action set file holds more than 1,000 actions o arquivo de conjunto de ações contém mais de 1.000 ações +@msg the action set file needs a later version of VectorCraft o arquivo de conjunto de ações requer uma versão mais recente do VectorCraft +@msg an action in the action set file has more than 10,000 steps uma ação do arquivo de conjunto de ações tem mais de 10.000 etapas @msg no such anchor âncora inexistente @msg no such artboard prancheta inexistente @msg the artboard is locked a prancheta está bloqueada diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv index 5afaa5167..bea46474c 100644 --- a/crates/ui-egui/src/i18n/ru.tsv +++ b/crates/ui-egui/src/i18n/ru.tsv @@ -2402,6 +2402,8 @@ diagnostics ui интерфейс Plates Пластины Platform: Платформа: Play Current Selection Воспроизвести текущее выделение + Save Actions… Сохранить действия… + Load Actions… Загрузить действия… Plug-in Info Сведения о модуле Plug-ins Модули Plug-in… Модуль… @@ -4277,6 +4279,14 @@ axis Both Оба @msg no selection bounds у выделения нет границ @msg no slice selected фрагмент не выделен @msg no such action такого действия нет +@msg no such action set такого набора действий нет +@msg the action sets changed; nothing was deleted наборы действий изменились; ничего не удалено +@msg no action set to save нет набора действий для сохранения +@msg not an action set file это не файл набора действий +@msg the action set file is larger than 8 MiB файл набора действий больше 8 MiB +@msg the action set file holds more than 1,000 actions файл набора действий содержит более 1000 действий +@msg the action set file needs a later version of VectorCraft для файла набора действий нужна более новая версия VectorCraft +@msg an action in the action set file has more than 10,000 steps в файле набора действий есть действие более чем из 10 000 шагов @msg no such anchor такой опорной точки нет @msg no such artboard такой монтажной области нет @msg the artboard is locked монтажная область заблокирована diff --git a/crates/ui-egui/src/i18n/sv.tsv b/crates/ui-egui/src/i18n/sv.tsv index 90c5bd949..17b4a6677 100644 --- a/crates/ui-egui/src/i18n/sv.tsv +++ b/crates/ui-egui/src/i18n/sv.tsv @@ -2314,6 +2314,8 @@ font-technology Variable Variabla Plates Plåtar Platform: Plattform: Play Current Selection Spela upp aktuell markering + Save Actions… Spara åtgärder… + Load Actions… Läs in åtgärder… Plug-in Info Information om plugin Plug-ins Plugins Plug-in… Plugin… @@ -4146,6 +4148,14 @@ axis Both Båda @msg no selection bounds inga markeringsgränser @msg no slice selected ingen skiva är markerad @msg no such action åtgärden finns inte +@msg no such action set åtgärdsuppsättningen finns inte +@msg the action sets changed; nothing was deleted åtgärdsuppsättningarna har ändrats; inget raderades +@msg no action set to save ingen åtgärdsuppsättning att spara +@msg not an action set file inte en fil med åtgärdsuppsättning +@msg the action set file is larger than 8 MiB filen med åtgärdsuppsättningen är större än 8 MiB +@msg the action set file holds more than 1,000 actions filen med åtgärdsuppsättningen innehåller fler än 1 000 åtgärder +@msg the action set file needs a later version of VectorCraft filen med åtgärdsuppsättningen kräver en nyare version av VectorCraft +@msg an action in the action set file has more than 10,000 steps en åtgärd i filen med åtgärdsuppsättningen har fler än 10 000 steg @msg no such anchor ankaret finns inte @msg no such artboard ritytan finns inte @msg the artboard is locked ritytan är låst diff --git a/crates/ui-egui/src/i18n/tr.tsv b/crates/ui-egui/src/i18n/tr.tsv index 5d3f51436..bd54fe47c 100644 --- a/crates/ui-egui/src/i18n/tr.tsv +++ b/crates/ui-egui/src/i18n/tr.tsv @@ -2189,6 +2189,8 @@ shape Open Açık Plates Plakalar Platform: Platform: Play Current Selection Geçerli Seçimi Oynat + Save Actions… Eylemleri Kaydet… + Load Actions… Eylemleri Yükle… Plug-in Info Eklenti Bilgisi Plug-ins Eklentiler Plug-in… Eklenti… @@ -4004,6 +4006,14 @@ axis Both Her İkisi @msg no selection bounds seçim sınırı yok @msg no slice selected dilim seçilmedi @msg no such action öyle bir eylem yok +@msg no such action set öyle bir eylem seti yok +@msg the action sets changed; nothing was deleted eylem setleri değişti; hiçbir şey silinmedi +@msg no action set to save kaydedilecek eylem seti yok +@msg not an action set file bir eylem seti dosyası değil +@msg the action set file is larger than 8 MiB eylem seti dosyası 8 MiB'den büyük +@msg the action set file holds more than 1,000 actions eylem seti dosyası 1.000'den fazla eylem içeriyor +@msg the action set file needs a later version of VectorCraft eylem seti dosyası VectorCraft'ın daha yeni bir sürümünü gerektiriyor +@msg an action in the action set file has more than 10,000 steps eylem seti dosyasındaki bir eylemde 10.000'den fazla adım var @msg no such anchor öyle bir çapa yok @msg no such artboard böyle bir çalışma yüzeyi yok @msg no such document öyle bir belge yok diff --git a/crates/ui-egui/src/i18n/uk.tsv b/crates/ui-egui/src/i18n/uk.tsv index f14471d32..18090209f 100644 --- a/crates/ui-egui/src/i18n/uk.tsv +++ b/crates/ui-egui/src/i18n/uk.tsv @@ -2399,6 +2399,8 @@ diagnostics ui інтерфейс Plates Пластини Platform: Платформа: Play Current Selection Відтворити поточне виділення + Save Actions… Зберегти дії… + Load Actions… Завантажити дії… Plug-in Info Відомості про модуль Plug-ins Модулі Plug-in… Модуль… @@ -4266,6 +4268,14 @@ axis Both Обидві @msg no selection bounds у виділення немає кордонів @msg no slice selected фрагмент не виділено @msg no such action такої дії немає +@msg no such action set такого набору дій немає +@msg the action sets changed; nothing was deleted набори дій змінилися; нічого не видалено +@msg no action set to save немає набору дій для збереження +@msg not an action set file це не файл набору дій +@msg the action set file is larger than 8 MiB файл набору дій більший за 8 MiB +@msg the action set file holds more than 1,000 actions файл набору дій містить понад 1000 дій +@msg the action set file needs a later version of VectorCraft для файлу набору дій потрібна новіша версія VectorCraft +@msg an action in the action set file has more than 10,000 steps у файлі набору дій є дія з понад 10 000 кроків @msg no such anchor такої опорної точки немає @msg no such artboard такої монтажної області немає @msg the artboard is locked монтажна область заблокована diff --git a/crates/ui-egui/src/i18n/vi.tsv b/crates/ui-egui/src/i18n/vi.tsv index f3246fb16..198eb64b7 100644 --- a/crates/ui-egui/src/i18n/vi.tsv +++ b/crates/ui-egui/src/i18n/vi.tsv @@ -2694,6 +2694,8 @@ diagnostics ui giao diện Plates Bản in Platform: Nền tảng: Play Current Selection Phát vùng chọn hiện tại + Save Actions… Lưu hành động… + Load Actions… Tải hành động… Plug-in Info Thông tin plug-in Plug-ins Plug-in Plug-in… Phần bổ trợ… @@ -4563,6 +4565,14 @@ theme Appearance Giao diện @msg no selection bounds vùng chọn không có giới hạn @msg no slice selected chưa chọn lát cắt @msg no such action không có hành động như vậy +@msg no such action set không có bộ hành động như vậy +@msg the action sets changed; nothing was deleted các bộ hành động đã thay đổi; không có gì bị xóa +@msg no action set to save không có bộ hành động nào để lưu +@msg not an action set file không phải tệp bộ hành động +@msg the action set file is larger than 8 MiB tệp bộ hành động lớn hơn 8 MiB +@msg the action set file holds more than 1,000 actions tệp bộ hành động chứa hơn 1.000 hành động +@msg the action set file needs a later version of VectorCraft tệp bộ hành động cần phiên bản VectorCraft mới hơn +@msg an action in the action set file has more than 10,000 steps một hành động trong tệp bộ hành động có hơn 10.000 bước @msg no such anchor không có điểm neo như vậy @msg no such artboard không có bảng vẽ như vậy @msg the artboard is locked bảng vẽ bị khóa diff --git a/crates/ui-egui/src/i18n/zh-hans.tsv b/crates/ui-egui/src/i18n/zh-hans.tsv index 082cdc70b..53ac5d929 100644 --- a/crates/ui-egui/src/i18n/zh-hans.tsv +++ b/crates/ui-egui/src/i18n/zh-hans.tsv @@ -2278,6 +2278,8 @@ diagnostics ui 界面 Plates 印版 Platform: 平台: Play Current Selection 播放当前选择项目 + Save Actions… 存储动作… + Load Actions… 载入动作… Plug-in Info 插件信息 Plug-ins 增效工具 Plug-in… 增效工具… @@ -4323,6 +4325,14 @@ imageTrace Outline 轮廓 @msg tool (a tool id) is required 需要 tool (工具 id) @msg unknown tool `{t}` 未知工具 `{t}` @msg no such action 没有此动作 +@msg no such action set 没有此动作组 +@msg the action sets changed; nothing was deleted 动作组已更改;未删除任何内容 +@msg no action set to save 没有要存储的动作组 +@msg not an action set file 不是动作组文件 +@msg the action set file is larger than 8 MiB 动作组文件大于 8 MiB +@msg the action set file holds more than 1,000 actions 动作组文件包含超过 1,000 个动作 +@msg the action set file needs a later version of VectorCraft 动作组文件需要更高版本的 VectorCraft +@msg an action in the action set file has more than 10,000 steps 动作组文件中有动作超过 10,000 个步骤 @msg choose a folder to export to 请选择要导出到的文件夹 @msg the selection has no URL (or they differ) 所选对象没有 URL (或其 URL 各不相同) @msg select some type first 请先选择一些文字 diff --git a/crates/ui-egui/src/i18n/zh-hant.tsv b/crates/ui-egui/src/i18n/zh-hant.tsv index ab4577e21..218e95a1d 100644 --- a/crates/ui-egui/src/i18n/zh-hant.tsv +++ b/crates/ui-egui/src/i18n/zh-hant.tsv @@ -2245,6 +2245,14 @@ file-filter Templates 範本 @msg tool (a tool id) is required 需要 tool (工具 id) @msg unknown tool `{t}` 未知的工具 `{t}` @msg no such action 沒有這個動作 +@msg no such action set 沒有這個動作組 +@msg the action sets changed; nothing was deleted 動作組已變更;未刪除任何內容 +@msg no action set to save 沒有要儲存的動作組 +@msg not an action set file 不是動作組檔案 +@msg the action set file is larger than 8 MiB 動作組檔案大於 8 MiB +@msg the action set file holds more than 1,000 actions 動作組檔案包含超過 1,000 個動作 +@msg the action set file needs a later version of VectorCraft 動作組檔案需要較新版本的 VectorCraft +@msg an action in the action set file has more than 10,000 steps 動作組檔案中有動作超過 10,000 個步驟 @msg choose a folder to export to 請選擇要匯出至的資料夾 @msg the selection has no URL (or they differ) 選取範圍沒有 URL (或其 URL 各不相同) @msg select some type first 請先選取一些文字 @@ -3239,6 +3247,8 @@ diagnostics ui 介面 Plates 色版 Platform: 平台: Play Current Selection 播放目前選取項目 + Save Actions… 儲存動作… + Load Actions… 載入動作… Plug-in Info 增效模組資訊 Plug-ins 增效模組 Plug-in… 增效模組… diff --git a/crates/ui-egui/src/io/save.rs b/crates/ui-egui/src/io/save.rs index 1e40b7a83..d7e6eabd2 100644 --- a/crates/ui-egui/src/io/save.rs +++ b/crates/ui-egui/src/io/save.rs @@ -127,6 +127,7 @@ const FILE_TYPES: &[(&str, &[&str])] = &[ ("PDF presets", vectorcraft_engine::cmd::pdfcmds::PRESET_EXTS), ("Perspective grid presets", vectorcraft_engine::cmd::perspgrid::PRESET_EXTS), ("Print presets", vectorcraft_engine::cmd::printpresets::PRESET_EXTS), + ("Action sets", &[crate::panels::actions::ACTIONS_EXT]), ("CSS", &["css"]), ("PostScript", &["ps"]), ]; diff --git a/crates/ui-egui/src/menus/run.rs b/crates/ui-egui/src/menus/run.rs index ea446081f..92a625174 100644 --- a/crates/ui-egui/src/menus/run.rs +++ b/crates/ui-egui/src/menus/run.rs @@ -789,6 +789,8 @@ fn run_ui_part11(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option crate::panels::actions::save_set(app, p), + crate::panels::actions::LOAD_SET => crate::panels::actions::load_set(app, p), crate::panels::actions::DELETE_SETS => crate::panels::actions::delete_sets(app, p), crate::panels::actions::DUPLICATE => crate::panels::actions::duplicate(app, p), "ui.shortcutImportDialog" => crate::dialogs::shortcut_import::command(app, p), diff --git a/crates/ui-egui/src/menus/ui_commands.rs b/crates/ui-egui/src/menus/ui_commands.rs index 381fa5436..f642d0ee1 100644 --- a/crates/ui-egui/src/menus/ui_commands.rs +++ b/crates/ui-egui/src/menus/ui_commands.rs @@ -1125,6 +1125,18 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[ "", "{set?: index, action?: index} open Batch (dialog `actionBatch`) for the action at set/action (default: the first action of the first set); OK runs action.batch with the dialog's source, destination and overrides", ), + ( + crate::panels::actions::SAVE_SET, + "Save Actions…", + "", + "{set?: index, id?, path?} write the Actions panel's set at set (0 is the top set; default: the current set) with its actions to an action set file (.vcactions) at path, else a picked file named after the set (the web downloads it). id holds the panel's own set id, which its menu passes: the set with this id is saved wherever it is now, and set is not read. A set over 8 MiB as a file, with more than 1,000 actions or with an action of more than 10,000 steps is not written; the panel menu's Save Actions… → {path}", + ), + ( + crate::panels::actions::LOAD_SET, + "Load Actions…", + "", + "{path? | data?: the file's text} read an action set file (.vcactions) at path, else a picked one, and add its set after the Actions panel's sets; a set named like one in the panel gets the next free number (Print 2), and the other sets stay. Files of another version, over 8 MiB, with more than 1,000 actions or with an action of more than 10,000 steps are refused; the panel menu's Load Actions… (disabled where there is no open dialog, the web) → {set: index, name, actions: n}", + ), ( crate::panels::actions::DELETE_SETS, "Delete Action Sets", diff --git a/crates/ui-egui/src/panels/actions.rs b/crates/ui-egui/src/panels/actions.rs index 49a818f14..30a95705c 100644 --- a/crates/ui-egui/src/panels/actions.rs +++ b/crates/ui-egui/src/panels/actions.rs @@ -10,6 +10,10 @@ use crate::theme::Tokens; use crate::widgets::{self, dim_label}; use crate::{VectorcraftApp, icons}; +mod files; +pub(crate) use files::can_load; +pub use files::{ACTIONS_EXT, LOAD_SET, SAVE_SET, load_set, save_set}; + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct Action { pub name: String, @@ -319,6 +323,20 @@ pub fn menu(app: &mut VectorcraftApp, ui: &mut egui::Ui) { { crate::dialogs::action_set_options::open_action(app, s, a); } + ui.separator(); + // As commands, so a file dialog shown off the UI thread saves or loads when it answers. + // Save Actions… names the current set by its id, so a file dialog that answers later saves that set. + let save = json!({ "id": current.and_then(|s| app.ui.action_sets.get(s)).map(|s| s.id) }); + for (label, id, on, params) in + [(tl!("Save Actions…"), SAVE_SET, current.is_some(), save), (tl!("Load Actions…"), LOAD_SET, can_load(app), json!({}))] + { + if widgets::menu_item(ui, label, on, false) + && let Err(e) = app.run(id, params) + && e != "cancelled" + { + app.status(e); + } + } } pub fn show(app: &mut VectorcraftApp, ui: &mut egui::Ui) { @@ -1246,4 +1264,136 @@ mod tests { play(&mut app, 0, spacing).unwrap(); assert_eq!(lefts(&app), [x0, x0 + 80.0, x1 - 20.0], "spaced across artboard 2, active when the action plays"); } + + /// Files in memory for `app`: what it writes, and what it reads back. Save dialogs pick + /// `/sets/` and the suggested name, open dialogs pick `open`. + fn with_files(app: &mut VectorcraftApp, open: &str) -> std::rc::Rc>>> { + let files = std::rc::Rc::new(std::cell::RefCell::new(std::collections::BTreeMap::>::new())); + let (w, r) = (files.clone(), files.clone()); + app.services.write = Some(Box::new(move |path: &str, bytes: &[u8]| { + w.borrow_mut().insert(path.to_string(), bytes.to_vec()); + Ok(()) + })); + app.services.read = Some(Box::new(move |path: &str| r.borrow().get(path).cloned().ok_or_else(|| "no such file".to_string()))); + app.services.pick_save = Some(Box::new(|pick: &crate::FilePick| Some(format!("/sets/{}", pick.name)))); + let open = open.to_string(); + app.services.pick_open = Some(Box::new(move |_: &crate::FilePick| Some(open.clone()))); + files + } + + /// The panel menu's Save Actions… writes the current set with its actions to a file named + /// after it, and Load Actions… adds the set it reads after the others, with the same actions + /// and steps; a set named like one in the panel gets the next free number, and the other sets + /// and the current set stay as they are. + #[test] + fn save_actions_and_load_actions_round_trip_a_set() { + use super::super::tests_appearance::{click, frame_events}; + let mut app = app_with_sets(); + let files = with_files(&mut app, "/sets/Mine.vcactions"); + let ctx = egui::Context::default(); + let item = |ctx: &egui::Context, app: &mut VectorcraftApp, label: &str| { + let texts = frame_events(ctx, app, vec![], menu); + texts.iter().find(|(s, _)| s.trim() == label).map(|(_, r)| r.center()).unwrap_or_else(|| panic!("{label} in the menu")) + }; + let save = item(&ctx, &mut app, "Save Actions…"); + click(&ctx, &mut app, save, menu); + assert!(files.borrow().is_empty(), "no set is current: nothing to save"); + click_set(&ctx, &mut app, "Mine", egui::Modifiers::NONE); + let save = item(&ctx, &mut app, "Save Actions…"); + click(&ctx, &mut app, save, menu); + let text = String::from_utf8(files.borrow()["/sets/Mine.vcactions"].clone()).unwrap(); + let v: Value = serde_json::from_str(&text).unwrap(); + assert_eq!((v["format"].clone(), v["version"].clone(), v["name"].clone()), (json!("vcactions"), json!(1), json!("Mine"))); + assert_eq!(v["actions"][1], json!({"name": "Nudge Again", "steps": [{"command": "object.move", "params": {"dx": 1, "dy": 0}}]})); + let load = item(&ctx, &mut app, "Load Actions…"); + click(&ctx, &mut app, load, menu); + assert_eq!(set_names(&app), ["Default Actions", "Mine", "Other", "Mine 2"], "added after the others, numbered"); + assert_eq!(app.ui.action_set, Some(1), "the current set stays"); + let steps = |s: &ActionSet| s.actions.iter().map(|a| (a.name.clone(), a.steps.clone())).collect::>(); + assert_eq!(steps(&app.ui.action_sets[3]), steps(&app.ui.action_sets[1]), "the same actions and steps"); + let r = app.run(LOAD_SET, json!({"data": text})).unwrap(); + assert_eq!(r, json!({"set": 4, "name": "Mine 3", "actions": 2})); + assert_ne!(app.ui.action_sets[3].id, app.ui.action_sets[4].id, "each loaded set has an id of its own"); + } + + /// `ui.actionSet.save` saves the set at `set`, else the current one, and `ui.actionSet.load` of + /// a set no other set is named like keeps its name; one with no name takes the file's. + #[test] + fn load_actions_adds_a_set_and_keeps_the_others() { + let mut app = app_with_sets(); + let files = with_files(&mut app, "/sets/Other.vcactions"); + assert_eq!(app.run(SAVE_SET, json!({})).unwrap_err(), "no action set to save"); + assert_eq!(app.run(SAVE_SET, json!({"set": 3})).unwrap_err(), "no such action set"); + assert_eq!(app.run(SAVE_SET, json!({"set": 1, "path": "/sets/kept.vcactions"})).unwrap(), json!({"path": "/sets/kept.vcactions"})); + let text = String::from_utf8(files.borrow()["/sets/kept.vcactions"].clone()).unwrap(); + app.run(DELETE_SETS, json!({"sets": [1]})).unwrap(); + assert_eq!(app.run(LOAD_SET, json!({"path": "/sets/kept.vcactions"})).unwrap(), json!({"set": 2, "name": "Mine", "actions": 2})); + assert_eq!(set_names(&app), ["Default Actions", "Other", "Mine"]); + let unnamed = text.replacen("\"name\": \"Mine\"", "\"name\": \"\"", 1); + files.borrow_mut().insert("/sets/Print Jobs.vcactions".into(), unnamed.into_bytes()); + assert_eq!(app.run(LOAD_SET, json!({"path": "/sets/Print Jobs.vcactions"})).unwrap()["name"], json!("Print Jobs")); + assert_eq!(app.run(SAVE_SET, json!({"set": 0, "path": "/sets/d.vcactions"})).unwrap(), json!({"path": "/sets/d.vcactions"})); + assert_eq!(files::set_file_stem("a/b: c?."), "a-b- c-"); + for (name, stem) in + [("CON", "CON-"), ("nul", "nul-"), ("Com1.print", "Com1-.print"), ("lpt²", "lpt²-"), ("COM10", "COM10"), ("Console", "Console")] + { + assert_eq!(files::set_file_stem(name), stem, "{name}"); + } + } + + /// A file that is not an action set file, or is too large, is refused with a message, and no + /// set is added. + #[test] + fn load_actions_refuses_a_file_that_is_not_an_action_set() { + let mut app = app_with_sets(); + let before = set_names(&app); + let many = json!({"format": "vcactions", "version": 1, "name": "Many", "actions": vec![json!({"name": "A", "steps": []}); 1001]}); + let steps = vec![json!({"command": "object.move"}); 10_001]; + let long = json!({"format": "vcactions", "version": 1, "name": "Long", "actions": [{"name": "A", "steps": steps}]}); + for (data, want) in [ + (json!("GIMP Palette"), "not an action set file (expected value at line 1 column 1)"), + (json!("{\"format\": \"vcstyles\", \"version\": 1, \"name\": \"S\", \"actions\": []}"), "not an action set file"), + (json!(42), "not an action set file"), + (json!(many.to_string()), "the action set file holds more than 1,000 actions"), + (json!(long.to_string()), "an action in the action set file has more than 10,000 steps"), + (json!(" ".repeat(files::MAX_SET_FILE + 1)), "the action set file is larger than 8 MiB"), + ( + json!("{\"format\": \"vcactions\", \"version\": 2, \"name\": \"S\", \"actions\": []}"), + "the action set file needs a later version of VectorCraft", + ), + ] { + assert_eq!(app.run(LOAD_SET, json!({ "data": data })).unwrap_err(), want); + } + with_files(&mut app, "/sets/missing.vcactions"); + assert_eq!(app.run(LOAD_SET, json!({})).unwrap_err(), "no such file"); + assert_eq!(set_names(&app), before, "no set added"); + } + + /// Save Actions… does not write a set that Load Actions… would refuse: more than 1,000 actions. + #[test] + fn save_actions_does_not_write_a_set_load_actions_refuses() { + let mut app = app_with_sets(); + let files = with_files(&mut app, "/sets/none.vcactions"); + app.ui.action_sets[2].actions = vec![Action { name: "A".into(), steps: vec![] }; 1001]; + let r = app.run(SAVE_SET, json!({"set": 2, "path": "/sets/big.vcactions"})); + assert_eq!(r.unwrap_err(), "the action set file holds more than 1,000 actions"); + assert!(files.borrow().is_empty(), "nothing written"); + } + + /// `ui.actionSet.save` with the set id the panel menu passes saves that set after another set + /// took its index and the current set changed, as when its file dialog answers later; an id + /// that no set has saves nothing, and `set` is not read. + #[test] + fn save_actions_saves_the_set_it_was_chosen_for() { + let mut app = app_with_sets(); + let files = with_files(&mut app, "/sets/none.vcactions"); + let id = app.ui.action_sets[2].id; + app.run(DELETE_SETS, json!({"sets": [1]})).unwrap(); + app.ui.action_sets.push(ActionSet::new("Third", vec![])); + app.ui.action_set = Some(2); + app.run(SAVE_SET, json!({"id": id, "path": "/sets/x.vcactions"})).unwrap(); + let v: Value = serde_json::from_slice(&files.borrow()["/sets/x.vcactions"]).unwrap(); + assert_eq!(v["name"], json!("Other"), "the set chosen, not the current one"); + assert_eq!(app.run(SAVE_SET, json!({"id": 0, "set": 0, "path": "/sets/y.vcactions"})).unwrap_err(), "no such action set"); + } } diff --git a/crates/ui-egui/src/panels/actions/files.rs b/crates/ui-egui/src/panels/actions/files.rs new file mode 100644 index 000000000..df5ffe852 --- /dev/null +++ b/crates/ui-egui/src/panels/actions/files.rs @@ -0,0 +1,187 @@ +//! Action set files: the Actions panel menu's Save Actions… and Load Actions…. +//! +//! An action set file (`.vcactions`) is JSON: `{"format": "vcactions", "version": 1, "name", +//! "actions": [{"name", "steps": [{"command", "params"}]}]}`. Each step is a command id and its +//! params, as `command.batch` takes them. + +use serde::{Deserialize, Serialize}; +use serde_json::{Value, json}; + +use super::{Action, ActionSet}; +use crate::VectorcraftApp; + +/// The command that saves an action set to a file ([`save_set`]). +pub const SAVE_SET: &str = "ui.actionSet.save"; + +/// The command that loads an action set from a file ([`load_set`]). +pub const LOAD_SET: &str = "ui.actionSet.load"; + +/// The extension of an action set file ([`write_set`]). +pub const ACTIONS_EXT: &str = "vcactions"; + +/// The largest action set file [`read_set`] reads. +pub(super) const MAX_SET_FILE: usize = 8 << 20; + +/// The most actions [`read_set`] reads from one file. +const MAX_SET_ACTIONS: usize = 1000; + +/// The most steps [`read_set`] reads in one action. +const MAX_ACTION_STEPS: usize = 10_000; + +/// An action set file: a header, the set's name and its actions. +#[derive(Serialize, Deserialize)] +struct SetFile { + format: String, + version: u32, + name: String, + actions: Vec, +} + +/// An action in an action set file. +#[derive(Serialize, Deserialize)] +struct FileAction { + name: String, + steps: Vec, +} + +/// A step of an action in an action set file: a command id and its params, as `command.batch` +/// takes them. +#[derive(Serialize, Deserialize)] +struct FileStep { + command: String, + #[serde(default)] + params: Value, +} + +/// `set` as the text of an action set file. +pub fn write_set(set: &ActionSet) -> String { + let actions = set + .actions + .iter() + .map(|a| FileAction { + name: a.name.clone(), + steps: a.steps.iter().map(|(command, params)| FileStep { command: command.clone(), params: params.clone() }).collect(), + }) + .collect(); + let file = SetFile { format: ACTIONS_EXT.into(), version: 1, name: set.name.clone(), actions }; + serde_json::to_string_pretty(&file).unwrap_or_default() +} + +/// The action set in the text of an action set file; a set without a name is called `name`. +pub fn read_set(text: &str, name: &str) -> Result { + if text.len() > MAX_SET_FILE { + return Err("the action set file is larger than 8 MiB".into()); + } + let f: SetFile = serde_json::from_str(text.trim_start_matches('\u{feff}')).map_err(|e| format!("not an action set file ({e})"))?; + if f.format != ACTIONS_EXT { + return Err("not an action set file".into()); + } + if f.version != 1 { + return Err("the action set file needs a later version of VectorCraft".into()); + } + if f.actions.len() > MAX_SET_ACTIONS { + return Err("the action set file holds more than 1,000 actions".into()); + } + if f.actions.iter().any(|a| a.steps.len() > MAX_ACTION_STEPS) { + return Err("an action in the action set file has more than 10,000 steps".into()); + } + let actions = + f.actions.into_iter().map(|a| Action { name: a.name, steps: a.steps.into_iter().map(|s| (s.command, s.params)).collect() }).collect(); + let set_name = if f.name.trim().is_empty() { name.to_string() } else { f.name }; + Ok(ActionSet::new(set_name, actions)) +} + +/// `name`, else `name 2`, `name 3` … : the first that no set in `sets` has. +fn free_set_name(sets: &[ActionSet], name: &str) -> String { + let taken = |n: &str| sets.iter().any(|s| s.name == n); + if !taken(name) { + return name.to_string(); + } + (2..).map(|n| format!("{name} {n}")).find(|n| !taken(n)).unwrap_or_else(|| name.to_string()) +} + +/// `name` as a file name: the characters file systems refuse become `-`, and a Windows device name +/// before the first period (`CON`, `PRN`, `AUX`, `NUL`, `COM1` to `COM9`, `LPT1` to `LPT9`, also +/// with `¹`, `²` or `³`, in any case) gets `-` after it, on every platform. +pub(super) fn set_file_stem(name: &str) -> String { + let stem: String = name.chars().map(|c| if c.is_control() || r#"/\:*?"<>|"#.contains(c) { '-' } else { c }).collect(); + let stem = stem.trim_matches(['.', ' ']); + if stem.is_empty() { + return "Actions".into(); + } + let (base, rest) = stem.split_at(stem.find('.').unwrap_or(stem.len())); + let base = base.trim_end_matches(' '); + let upper = base.to_ascii_uppercase(); + let numbered = |n: &str| n.chars().count() == 1 && n.chars().all(|c| matches!(c, '1'..='9' | '¹' | '²' | '³')); + let device = matches!(upper.as_str(), "CON" | "PRN" | "AUX" | "NUL") + || upper.strip_prefix("COM").or_else(|| upper.strip_prefix("LPT")).is_some_and(numbered); + if device { format!("{base}-{rest}") } else { stem.to_string() } +} + +/// `ui.actionSet.save {set?: index, id?, path?}`: writes the action set at `set` (default: the +/// current set) with its actions to an action set file at `path`, else a picked file named after +/// the set (the web downloads it) → `{path}`. `id` is the panel's own set id ([`ActionSet::id`]), +/// which the panel menu passes: the set with this id is saved wherever it is when the file dialog +/// answers, and `set` is not read. A set that [`read_set`] would refuse (larger than 8 MiB as a +/// file, more than 1,000 actions, an action with more than 10,000 steps) is not written. +pub fn save_set(app: &mut VectorcraftApp, p: &Value) -> Result { + let len = app.ui.action_sets.len(); + let set = match (p.get("id"), p.get("set")) { + (Some(id), _) if !id.is_null() => { + id.as_u64().and_then(|id| app.ui.action_sets.iter().position(|s| s.id == id)).ok_or("no such action set")? + } + (_, None | Some(Value::Null)) => app.ui.action_set.filter(|&s| s < len).ok_or("no action set to save")?, + (_, Some(v)) => v.as_u64().and_then(|i| usize::try_from(i).ok()).filter(|&i| i < len).ok_or("no such action set")?, + }; + let Some(s) = app.ui.action_sets.get(set) else { return Err("no such action set".into()) }; + let text = write_set(s); + // What Save Actions… writes, Load Actions… reads back. + read_set(&text, "")?; + let name = format!("{}.{ACTIONS_EXT}", set_file_stem(&s.name)); + let path = p.get("path").and_then(Value::as_str).map(str::to_string); + let path = crate::io::write_named(app, path, &name, text.as_bytes())?; + app.status(format!("Saved {path}")); + Ok(json!({ "path": path })) +} + +/// Whether Load Actions… can ask for a file: not where there is no open dialog (the web). +pub(crate) fn can_load(app: &VectorcraftApp) -> bool { + crate::picks::can(app, &crate::picks::PickRequest::Open(crate::FilePick::default())) +} + +/// `ui.actionSet.load {path? | data?}`: reads the action set file at `path` (else a picked one), or +/// the file's text `data`, and adds its set after the others, with its actions. A set with the +/// same name as one in the panel gets the next free number (`Print 2`). The current set and the +/// other sets stay as they are → `{set: index, name, actions: n}`. +pub fn load_set(app: &mut VectorcraftApp, p: &Value) -> Result { + let (text, stem) = match p.get("data") { + Some(Value::String(data)) => { + // Checked before the copy: `read_set` checks it again. + if data.len() > MAX_SET_FILE { + return Err("the action set file is larger than 8 MiB".into()); + } + (data.clone(), String::new()) + } + Some(_) => return Err("not an action set file".into()), + None => { + let path = match p.get("path").and_then(Value::as_str) { + Some(path) => path.to_string(), + None => { + let pick = crate::FilePick { filters: vec![crate::FilePick::filter("Action sets", &[ACTIONS_EXT])], ..Default::default() }; + crate::picks::open(app, &pick).ok_or("cancelled")? + } + }; + let bytes = app.services.read.as_ref().ok_or("no file reader")?(&path)?; + if bytes.len() > MAX_SET_FILE { + return Err("the action set file is larger than 8 MiB".into()); + } + let stem = std::path::Path::new(&path).file_stem().map(|s| s.to_string_lossy().into_owned()).unwrap_or_default(); + (String::from_utf8(bytes).map_err(|_| "not an action set file")?, stem) + } + }; + let mut set = read_set(&text, if stem.is_empty() { "Actions" } else { &stem })?; + set.name = free_set_name(&app.ui.action_sets, &set.name); + let (name, actions) = (set.name.clone(), set.actions.len()); + app.ui.action_sets.push(set); + Ok(json!({ "set": app.ui.action_sets.len() - 1, "name": name, "actions": actions })) +} diff --git a/crates/ui-egui/src/picks.rs b/crates/ui-egui/src/picks.rs index 736b42dc0..362108a46 100644 --- a/crates/ui-egui/src/picks.rs +++ b/crates/ui-egui/src/picks.rs @@ -70,6 +70,8 @@ const DOCUMENT_FREE: &[&str] = &[ "shortcuts.import", "shortcuts.export", "ui.shortcutImportDialog", + crate::panels::actions::SAVE_SET, + crate::panels::actions::LOAD_SET, ]; impl Entry { diff --git a/docs/mcp.md b/docs/mcp.md index 79afd672b..40fe307d3 100644 --- a/docs/mcp.md +++ b/docs/mcp.md @@ -1698,6 +1698,20 @@ 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). +- Action set files: `ui.actionSet.save {set?: index, id?, path?}` writes the Actions panel's set at `set` (0 is the + top set; by default the current set) with its actions to an action set file at `path`, else a picked file named + after the set (the web downloads it), and returns `{path}`. `id` holds the panel's own set id, which the panel menu + passes: the set with this id is saved wherever it is when the file dialog answers, and `set` is not read. A set that + would be larger than 8 MiB as a file, has more than 1,000 actions or has an action of more than 10,000 steps is not + written, and the command returns the same error as a load of such a file. `ui.actionSet.load {path? | data?}` reads + the file at `path`, else a picked one, or the file's text `data`, adds its set after the other sets and returns + `{set, name, actions}`. A set named like one already in the panel gets the next free number (`Print 2`), and the + other sets and the current set stay as they are. An action set file (`.vcactions`) is JSON: + `{"format": "vcactions", "version": 1, "name", "actions": [{"name", "steps": [{"command", "params"}]}]}`, each step + a command id and its params as `command.batch` takes them. A file with another `format` or a `version` other than + 1, a file larger than 8 MiB, one with more than 1,000 actions and one with an action of more than 10,000 steps are + refused, and no set is added. The Actions panel menu's Save Actions… and Load Actions… run these; Load Actions… is + disabled where there is no open dialog (the web). - 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… diff --git a/docs/target-app-parity.md b/docs/target-app-parity.md index a147941f2..ac391a5e7 100644 --- a/docs/target-app-parity.md +++ b/docs/target-app-parity.md @@ -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 menu: Save Actions… writes the current action set with all its actions to a file, and Load Actions… adds the set from such a file to the panel ([Manage a set of actions](https://helpx.adobe.com/illustrator/desktop/automate-visualize-data/automate-actions/manage-a-set-of-actions.html): "Select Save Actions from the Actions panel menu", "You can save only the entire contents of a set", "Select Load Actions from the Actions panel menu"; `ui.actionSet.save`, `ui.actionSet.load`). The file is VectorCraft's own action set file (`.vcactions`); a loaded set named like one in the panel gets the next free number. - 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. diff --git a/docs/ui-parity.md b/docs/ui-parity.md index 6bcd5ac1a..26e392ad6 100644 --- a/docs/ui-parity.md +++ b/docs/ui-parity.md @@ -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 (). 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: ≡ › Save Actions… saves the current set with all its actions to a file and ≡ › Load Actions… adds a saved set ([Manage a set of actions](https://helpx.adobe.com/illustrator/desktop/automate-visualize-data/automate-actions/manage-a-set-of-actions.html)) | partial | `ui.actionSet.save`, `ui.actionSet.load`; `panels/actions.rs` tests. The file is VectorCraft's own `.vcactions` JSON; the reference app's `.aia` files and Reset, Clear and Replace Actions remain | | 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 |