Merge pull request #5192 from dotCooCoo/feat/save-load-actions

Actions: Save Actions… and Load Actions… save a set to a file and load it back
This commit is contained in:
BFlat
2026-11-02 14:51:50 +07:00
committed by GitHub
35 changed files with 630 additions and 0 deletions
+10
View File
@@ -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 работната област е заключена
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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á
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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 ο πίνακας σχεδίασης είναι κλειδωμένος
Can't render this file because it contains an unexpected character in line 163 and column 5.
+10
View File
@@ -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
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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é
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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
Can't render this file because it contains an unexpected character in line 2196 and column 5.
+10
View File
@@ -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
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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 先にテキストを選択してください
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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 სამუშაო დაფა ჩაკეტილია
Can't render this file because it is too large.
+10
View File
@@ -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 먼저 문자를 선택하세요
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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
Can't render this file because it contains an unexpected character in line 6 and column 47.
+10
View File
@@ -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 монтажная область заблокирована
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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
Can't render this file because it contains an unexpected character in line 5 and column 25.
+10
View File
@@ -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
Can't render this file because it contains an unexpected character in line 5 and column 25.
+10
View File
@@ -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 монтажна область заблокована
Can't render this file because it contains an unexpected character in line 177 and column 5.
+10
View File
@@ -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
Can't render this file because it contains an unexpected character in line 199 and column 5.
+10
View File
@@ -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 请先选择一些文字
Can't render this file because it contains an unexpected character in line 2 and column 73.
+10
View File
@@ -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… 增效模組…
Can't render this file because it contains an unexpected character in line 6 and column 47.
+1
View File
@@ -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"]),
];
+2
View File
@@ -789,6 +789,8 @@ fn run_ui_part11(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option<Result
let action = p.get("action").and_then(Value::as_u64).unwrap_or(0) as usize;
crate::dialogs::action_batch::open(app, set, action)
}
crate::panels::actions::SAVE_SET => 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),
+12
View File
@@ -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",
+150
View File
@@ -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<std::cell::RefCell<std::collections::BTreeMap<String, Vec<u8>>>> {
let files = std::rc::Rc::new(std::cell::RefCell::new(std::collections::BTreeMap::<String, Vec<u8>>::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::<Vec<_>>();
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");
}
}
+187
View File
@@ -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<FileAction>,
}
/// An action in an action set file.
#[derive(Serialize, Deserialize)]
struct FileAction {
name: String,
steps: Vec<FileStep>,
}
/// 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<ActionSet, String> {
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<Value, String> {
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<Value, String> {
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 }))
}
+2
View File
@@ -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 {
+14
View File
@@ -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…
+1
View File
@@ -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.
+1
View File
@@ -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: ≡ › 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 |