Merge pull request #7050 from dotCooCoo/feat/layers-delete-confirm

Layers: deleting layers that hold art asks first
This commit is contained in:
BFlat
2026-11-13 13:18:43 +07:00
committed by GitHub
36 changed files with 298 additions and 9 deletions
+6
View File
@@ -945,6 +945,12 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[
"",
"{ids?|id?} open Layer Options for Layers panel rows (default: the highlighted rows, else the current layer), filled in from the first: dialog `layerOptions`, fields name, color (a preset name such as \"Light Blue\" or #rrggbb), template, locked, visible, printable, preview, dimImages (bool), dimPercent (0–100); an object's row has name, visible and locked. OK runs layer.setProps (one undo step); for several rows it sends only the fields set in the dialog",
),
(
"ui.layerDelete",
"Delete Selection",
"",
"{ids?|id?, doc?, confirmed?: bool} Delete Selection as the Layers panel runs it (its trash button, rows dropped on the trash, its menu, Delete and Backspace), on the rows layer.delete takes (default: the highlighted rows, else the current layer). When a layer or sublayer among them holds art (an object other than a guide; hidden, locked and nested objects count) it asks first: dialog `confirm` with `message`; OK deletes those rows by id with layer.delete (one undo step), Cancel keeps them. OK runs ui.layerDelete again with the rows, `doc` (the document's uid) and `confirmed: true`: with another document active then, nothing is deleted. Other rows (an empty layer, groups and objects alone) and rows layer.delete refuses go to layer.delete at once → layer.delete's {deleted}, or null while the question is open",
),
(
"ui.rename",
"Rename",
+2
View File
@@ -797,6 +797,8 @@ font-technology Variable Променливи
Delete Width Point Изтриване на точка на ширината
Delete Workspace Изтриване на работно пространство
Delete {kind} Style Изтриване на стил ({kind})
Delete the selected items and their artwork? Да се изтрият ли избраните елементи заедно с графиката им?
Delete this layer and its artwork? Да се изтрие ли този слой заедно с графиката му?
Delete “{name}”? Изтриване на „{name}“?
Depth: Дълбочина:
Description Описание
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2
View File
@@ -2145,6 +2145,8 @@ digits Malayalam Malajalam
Weight: Debljina:
Art using a deleted global swatch keeps its colour. Crtež koji koristi izbrisani globalni uzorak boje zadržava svoju boju.
Color Group: {name} Grupa boja: {name}
Delete the selected items and their artwork? Izbrisati odabrane stavke zajedno s njihovim crtežom?
Delete this layer and its artwork? Izbrisati ovaj sloj zajedno s njegovim crtežom?
Delete “{name}”? Izbrisati „{name}”?
Document Swatches Uzorci boja dokumenta
Edit or Apply Color Group Uredi ili primijeni grupu boja
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -1163,6 +1163,8 @@ antiAlias Sharp Nítid
Delete Width Point Suprimeix el punt d’amplada
Delete Workspace Suprimeix l’espai de treball
Delete {kind} Style Suprimeix l’estil de {kind}
Delete the selected items and their artwork? Voleu suprimir els elements seleccionats i el seu art?
Delete this layer and its artwork? Voleu suprimir aquesta capa i el seu art?
Delete “{name}”? Voleu suprimir “{name}”?
Depth Profunditat
Depth: Profunditat:
@@ -6040,6 +6042,7 @@ digits Malayalam Malaiàlam
@msg t, dx and dy must be finite t, dx i dy han de ser finits
@msg Targa files are RGB: colorModel rgb Els fitxers Targa són RGB: colorModel rgb
@msg Text Wrap: select a wrap object Ajustament de text: selecciona un objecte d’ajustament
@msg the active document changed while the question was open; nothing was deleted el document actiu ha canviat mentre la pregunta era oberta; no s’ha suprimit res
@msg that document is no longer open aquest document ja no està obert
@msg Extrude & Bevel Extrudeix i bisella
@msg Revolve Revoluciona
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -2176,6 +2176,8 @@ digits Malayalam Malajálamské
Weight: Tloušťka:
Art using a deleted global swatch keeps its colour. Kresba, která používá odstraněnou globální položku vzorníku, si barvu ponechá.
Color Group: {name} Skupina barev: {name}
Delete the selected items and their artwork? Odstranit vybrané položky i s kresbou?
Delete this layer and its artwork? Odstranit tuto vrstvu i s kresbou?
Delete “{name}”? Odstranit „{name}“?
Document Swatches Vzorník dokumentu
Edit or Apply Color Group Upravit nebo použít skupinu barev
@@ -5402,6 +5404,7 @@ imageTrace Outline Obrys
@msg choose the font files to add vyberte soubory písem, které chcete přidat
@msg not a file nejde o soubor
@msg not a font file nejde o soubor písma
@msg the active document changed while the question was open; nothing was deleted aktivní dokument se změnil, zatímco byla otázka otevřená; nic nebylo odstraněno
@msg that document is no longer open tento dokument už není otevřen
@msg larger than 256 MB větší než 256 MB
@msg the files come to more than 1 GB: add fewer at a time soubory mají dohromady více než 1 GB: přidávejte jich méně najednou
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2
View File
@@ -1978,6 +1978,8 @@ digits Malayalam Malayalam
Weight: Vægt:
Art using a deleted global swatch keeps its colour. Grafik, der bruger en slettet global farveprøve, bevarer sin farve.
Color Group: {name} Farvegruppe: {name}
Delete the selected items and their artwork? Slet de valgte elementer og deres grafik?
Delete this layer and its artwork? Slet dette lag og dets grafik?
Delete “{name}”? Slet »{name}«?
Document Swatches Dokumentfarveprøver
Edit or Apply Color Group Redigér eller anvend farvegruppe
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -791,6 +791,8 @@ font-technology Variable Variabel
Delete Width Point Breitenpunkt löschen
Delete Workspace Arbeitsbereich löschen
Delete {kind} Style {kind}format löschen
Delete the selected items and their artwork? Die ausgewählten Elemente und ihr Bildmaterial löschen?
Delete this layer and its artwork? Diese Ebene und ihr Bildmaterial löschen?
Delete “{name}”? „{name}“ löschen?
Depth: Tiefe:
Description Beschreibung
@@ -5019,6 +5021,7 @@ theme Appearance Erscheinungsbild
@msg choose the font files to add wählen Sie die Schriftdateien aus, die hinzugefügt werden sollen
@msg not a file keine Datei
@msg not a font file keine Schriftdatei
@msg the active document changed while the question was open; nothing was deleted das aktive Dokument hat sich geändert, während die Frage offen war; es wurde nichts gelöscht
@msg that document is no longer open dieses Dokument ist nicht mehr geöffnet
@msg larger than 256 MB größer als 256 MB
@msg the files come to more than 1 GB: add fewer at a time die Dateien sind zusammen größer als 1 GB: Fügen Sie weniger auf einmal hinzu
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -771,6 +771,8 @@ font-technology Variable Μεταβλητές
Delete Width Point Διαγραφή σημείου πλάτους
Delete Workspace Διαγραφή χώρου εργασίας
Delete {kind} Style Διαγραφή στυλ {kind}
Delete the selected items and their artwork? Να διαγραφούν τα επιλεγμένα στοιχεία και τα γραφικά τους;
Delete this layer and its artwork? Να διαγραφεί αυτό το επίπεδο και τα γραφικά του;
Delete “{name}”? Να διαγραφεί το «{name}»;
Depth: Βάθος:
Description Περιγραφή
@@ -5041,6 +5043,7 @@ digits Malayalam Μαλαγιάλαμ
@msg choose the font files to add επιλέξτε τα αρχεία γραμματοσειρών που θέλετε να προσθέσετε
@msg not a file δεν είναι αρχείο
@msg not a font file δεν είναι αρχείο γραμματοσειράς
@msg the active document changed while the question was open; nothing was deleted το ενεργό έγγραφο άλλαξε ενώ η ερώτηση ήταν ανοιχτή· δεν διαγράφηκε τίποτα
@msg that document is no longer open αυτό το έγγραφο δεν είναι πλέον ανοιχτό
@msg larger than 256 MB μεγαλύτερο από 256 MB
@msg the files come to more than 1 GB: add fewer at a time τα αρχεία ξεπερνούν το 1 GB: προσθέστε λιγότερα κάθε φορά
Can't render this file because it is too large.
+3
View File
@@ -812,6 +812,8 @@ font-technology Variable Variables
Delete Width Point Eliminar punto de anchura
Delete Workspace Eliminar espacio de trabajo
Delete {kind} Style Eliminar estilo de {kind}
Delete the selected items and their artwork? ¿Eliminar los elementos seleccionados y su ilustración?
Delete this layer and its artwork? ¿Eliminar esta capa y su ilustración?
Delete “{name}”? ¿Eliminar “{name}”?
Depth: Profundidad:
Description Descripción
@@ -5094,6 +5096,7 @@ axis Both Ambos
@msg choose the font files to add elige los archivos de fuentes que quieres agregar
@msg not a file no es un archivo
@msg not a font file no es un archivo de fuente
@msg the active document changed while the question was open; nothing was deleted el documento activo cambió mientras la pregunta estaba abierta; no se eliminó nada
@msg that document is no longer open ese documento ya no está abierto
@msg larger than 256 MB mayor de 256 MB
@msg the files come to more than 1 GB: add fewer at a time los archivos suman más de 1 GB: agrega menos a la vez
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -2137,6 +2137,8 @@ digits Malayalam Malajalam
Weight: Paksuus:
Art using a deleted global swatch keeps its colour. Poistettua globaalia värimallia käyttävä kuvitus säilyttää värinsä.
Color Group: {name} Väriryhmä: {name}
Delete the selected items and their artwork? Poistetaanko valitut kohteet ja niiden kuvitus?
Delete this layer and its artwork? Poistetaanko tämä taso ja sen kuvitus?
Delete “{name}”? Poistetaanko ”{name}”?
Document Swatches Asiakirjan värimallit
Edit or Apply Color Group Muokkaa tai käytä väriryhmää
@@ -5302,6 +5304,7 @@ imageTrace Outline Ääriviiva
@msg choose the font files to add valitse lisättävät fonttitiedostot
@msg not a file ei tiedosto
@msg not a font file ei fonttitiedosto
@msg the active document changed while the question was open; nothing was deleted aktiivinen asiakirja vaihtui kysymyksen ollessa auki; mitään ei poistettu
@msg that document is no longer open kyseinen asiakirja ei ole enää auki
@msg larger than 256 MB suurempi kuin 256 MB
@msg the files come to more than 1 GB: add fewer at a time tiedostojen koko on yli 1 GB: lisää vähemmän kerrallaan
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -815,6 +815,8 @@ font-technology Variable Variables
Delete Width Point Supprimer le point de largeur
Delete Workspace Supprimer l’espace de travail
Delete {kind} Style Supprimer le style de {kind}
Delete the selected items and their artwork? Supprimer les éléments sélectionnés et leur illustration ?
Delete this layer and its artwork? Supprimer ce calque et son illustration ?
Delete “{name}”? Supprimer « {name} » ?
Depth: Profondeur :
Description Description
@@ -5081,6 +5083,7 @@ axis Both Les deux
@msg choose the font files to add choisissez les fichiers de polices à ajouter
@msg not a file n’est pas un fichier
@msg not a font file n’est pas un fichier de police
@msg the active document changed while the question was open; nothing was deleted le document actif a changé pendant que la question était ouverte ; rien n’a été supprimé
@msg that document is no longer open ce document n’est plus ouvert
@msg larger than 256 MB plus de 256 Mo
@msg the files come to more than 1 GB: add fewer at a time les fichiers dépassent 1 Go : ajoutez-en moins à la fois
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -1222,6 +1222,8 @@ antiAlias Sharp शार्प
Define Perspective Grid… पर्सपेक्टिव ग्रिड डिफ़ाइन करें…
Definition परिभाषा
Delete हटाएँ
Delete the selected items and their artwork? चुने गए आइटम और उनका आर्टवर्क हटाएँ?
Delete this layer and its artwork? यह लेयर और इसका आर्टवर्क हटाएँ?
Delete “{name}”? "{name}" को हटाएं?
Delete {kind} Style Delete {kind} Style
Delete Action Sets एक्शन सेट हटाएं
@@ -7833,6 +7835,7 @@ antiAlias Sharp शार्प
@msg textureImage: {e} textureImage: {e}
@msg textureImage: give {path} or {name, dataBase64} of an image file, or a texture as effect.list gives it textureImage: किसी इमेज फ़ाइल का {path} या {name, dataBase64} दें, या effect.list द्वारा दिया गया टेक्सचर दें
@msg that anchor can't slide: an end of an open path has nowhere to go कि एंकर स्लाइड नहीं कर सकते: एक खुले रास्ते का अंत कहीं नहीं जाना है
@msg the active document changed while the question was open; nothing was deleted प्रश्न खुला रहते हुए सक्रिय डॉक्यूमेंट बदल गया; कुछ भी नहीं हटाया गया
@msg that document is no longer open यह डॉक्यूमेंट अब खुला नहीं है
@msg that makes more than {MAX_PIECES} slices जो {MAX_PIECES} स्लाइस से अधिक बनाता है
@msg that makes too many pieces (at most 100000): make the dashes longer जो बहुत सारे टुकड़े बनाता है (अधिकांश 100000 में): डैश को लंबे समय तक बनाते हैं
Can't render this file because it is too large.
+3
View File
@@ -1042,6 +1042,8 @@ font-technology Variable Változó
Delete Width Point Szélességi pont törlése
Delete Workspace Munkaterület törlése
Delete {kind} Style Stílus törlése: {kind}
Delete the selected items and their artwork? Törlöd a kijelölt elemeket a grafikájukkal együtt?
Delete this layer and its artwork? Törlöd ezt a réteget a grafikájával együtt?
Delete “{name}”? Törlöd ezt: „{name}”?
Depth: Színmélység:
Descender Lenyúló szár
@@ -5604,6 +5606,7 @@ imageTrace Outline Körvonal
@msg SVG parse error: {0} SVG-elemzési hiba: {0}
@msg Targa files are RGB: colorModel rgb a Targa-fájlok RGB-k: colorModel rgb
@msg Text Wrap: select a wrap object Szöveg körbefuttatása: jelölj ki egy körbefuttató objektumot
@msg the active document changed while the question was open; nothing was deleted az aktív dokumentum megváltozott, amíg a kérdés nyitva volt; semmi sem lett törölve
@msg that document is no longer open az a dokumentum már nincs megnyitva
@msg the art could not be sampled a grafikából nem sikerült mintát venni
@msg the art has no bounds a grafikának nincsenek határai
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2
View File
@@ -1978,6 +1978,8 @@ digits Malayalam Malayalam
Weight: Ketebalan:
Art using a deleted global swatch keeps its colour. Karya seni yang memakai swatch global terhapus tetap mempertahankan warnanya.
Color Group: {name} Grup warna: {name}
Delete the selected items and their artwork? Hapus item yang dipilih beserta karya seninya?
Delete this layer and its artwork? Hapus lapisan ini beserta karya seninya?
Delete “{name}”? Hapus “{name}”?
Document Swatches Swatch dokumen
Edit or Apply Color Group Edit atau terapkan grup warna
1 # Indonesian (id) catalog. Same format as zh-hant.tsv: context <TAB> source <TAB> translation
1978
1979
1980
1981
1982
1983
1984
1985
+3
View File
@@ -812,6 +812,8 @@ font-technology Variable Variabili
Delete Width Point Elimina punto di larghezza
Delete Workspace Elimina area di lavoro
Delete {kind} Style Elimina stile {kind}
Delete the selected items and their artwork? Eliminare gli elementi selezionati e la loro grafica?
Delete this layer and its artwork? Eliminare questo livello e la sua grafica?
Delete “{name}”? Eliminare “{name}”?
Depth: Profondità:
Description Descrizione
@@ -5145,6 +5147,7 @@ axis Both Entrambi
@msg choose the font files to add scegli i file dei font da aggiungere
@msg not a file non è un file
@msg not a font file non è un file di font
@msg the active document changed while the question was open; nothing was deleted il documento attivo è cambiato mentre la domanda era aperta; non è stato eliminato nulla
@msg that document is no longer open quel documento non è più aperto
@msg larger than 256 MB più grande di 256 MB
@msg the files come to more than 1 GB: add fewer at a time i file superano 1 GB: aggiungine meno alla volta
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -1475,6 +1475,8 @@ antiAlias Sharp シャープ
Delete theme テーマを削除
Delete this saved preset この保存済みプリセットを削除
Delete {kind} Style {kind}スタイルを削除
Delete the selected items and their artwork? 選択した項目とそのアートワークを削除しますか?
Delete this layer and its artwork? このレイヤーとそのアートワークを削除しますか?
Delete “{name}”? 「{name}」を削除しますか?
Depth: 深さ:
Description 説明
@@ -5212,6 +5214,7 @@ swatch Bright Violet ビビッドバイオレット
@msg choose the font files to add 追加するフォントファイルを選択してください
@msg not a file ファイルではありません
@msg not a font file フォントファイルではありません
@msg the active document changed while the question was open; nothing was deleted 質問が開いている間にアクティブなドキュメントが変わったため、何も削除されませんでした
@msg that document is no longer open そのドキュメントはもう開かれていません
@msg larger than 256 MB 256 MB を超えています
@msg the files come to more than 1 GB: add fewer at a time ファイルの合計が 1 GB を超えています: 一度に追加するファイルを減らしてください
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -1907,6 +1907,8 @@ digits Malayalam მალაიალამური
Weight: სისქე:
Art using a deleted global swatch keeps its colour. წაშლილი გლობალური ფერის ნიმუშის მქონე ნახატი თავის ფერს ინარჩუნებს.
Color Group: {name} ფერთა ჯგუფი: {name}
Delete the selected items and their artwork? წაიშალოს მონიშნული ელემენტები და მათი ნახატი?
Delete this layer and its artwork? წაიშალოს ეს შრე და მისი ნახატი?
Delete “{name}”? წაიშალოს „{name}“?
Document Swatches დოკუმენტის ფერის ნიმუშები
Edit or Apply Color Group ფერთა ჯგუფის რედაქტირება ან გამოყენება
@@ -4739,6 +4741,7 @@ font-technology Variable ცვლადი
@msg choose the font files to add აირჩიეთ დასამატებელი შრიფტის ფაილები
@msg not a file ფაილი არ არის
@msg not a font file შრიფტის ფაილი არ არის
@msg the active document changed while the question was open; nothing was deleted აქტიური დოკუმენტი შეიცვალა, სანამ კითხვა ღია იყო; არაფერი წაშლილა
@msg that document is no longer open ის დოკუმენტი აღარ არის გახსნილი
@msg larger than 256 MB 256 MB-ზე დიდია
@msg the files come to more than 1 GB: add fewer at a time ფაილები 1 GB-ს აჭარბებს: დაამატეთ ნაკლები ერთდროულად
Can't render this file because it is too large.
+3
View File
@@ -1465,6 +1465,8 @@ antiAlias Sharp 날카롭게
Delete theme 테마 삭제
Delete this saved preset 저장된 이 프리셋 삭제
Delete {kind} Style {kind} 스타일 삭제
Delete the selected items and their artwork? 선택한 항목과 해당 아트워크를 삭제하시겠습니까?
Delete this layer and its artwork? 이 레이어와 해당 아트워크를 삭제하시겠습니까?
Delete “{name}”? “{name}”을(를) 삭제하시겠습니까?
Depth: 깊이:
Description 설명
@@ -5139,6 +5141,7 @@ theme Appearance 외관
@msg choose the font files to add 추가할 글꼴 파일을 선택하세요
@msg not a file 파일이 아닙니다
@msg not a font file 글꼴 파일이 아닙니다
@msg the active document changed while the question was open; nothing was deleted 질문이 열려 있는 동안 활성 문서가 바뀌어 아무것도 삭제되지 않았습니다
@msg that document is no longer open 해당 문서는 더 이상 열려 있지 않습니다
@msg larger than 256 MB 256MB보다 큽니다
@msg the files come to more than 1 GB: add fewer at a time 파일의 합계가 1GB를 넘습니다: 한 번에 적게 추가하세요
Can't render this file because it contains an unexpected character in line 2 and column 73.
+2
View File
@@ -1992,6 +1992,8 @@ digits Malayalam Malayalam
Weight: Dikte:
Art using a deleted global swatch keeps its colour. Artwork met een verwijderd globaal staal behoudt zijn kleur.
Color Group: {name} Kleurgroep: {name}
Delete the selected items and their artwork? De geselecteerde items en hun artwork verwijderen?
Delete this layer and its artwork? Deze laag en het artwork erin verwijderen?
Delete “{name}”? „{name}” verwijderen?
Document Swatches Documentstalen
Edit or Apply Color Group Kleurgroep bewerken of toepassen
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -2094,6 +2094,8 @@ digits Malayalam Malajalam
Weight: Grubość:
Art using a deleted global swatch keeps its colour. Kompozycja używająca usuniętej próbki globalnej zachowa swój kolor.
Color Group: {name} Grupa kolorów: {name}
Delete the selected items and their artwork? Usunąć zaznaczone elementy razem z grafiką?
Delete this layer and its artwork? Usunąć tę warstwę razem z grafiką?
Delete “{name}”? Usunąć „{name}”?
Document Swatches Próbki dokumentu
Edit or Apply Color Group Edytuj lub zastosuj grupę kolorów
@@ -5228,6 +5230,7 @@ imageTrace Outline Kontur
@msg choose the font files to add wybierz pliki czcionek do dodania
@msg not a file to nie jest plik
@msg not a font file to nie jest plik czcionki
@msg the active document changed while the question was open; nothing was deleted aktywny dokument zmienił się, gdy pytanie było otwarte; nic nie zostało usunięte
@msg that document is no longer open ten dokument nie jest już otwarty
@msg larger than 256 MB większy niż 256 MB
@msg the files come to more than 1 GB: add fewer at a time pliki przekraczają łącznie 1 GB: dodawaj mniej naraz
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -725,6 +725,8 @@ antiAlias Sharp Nítido
Delete theme Excluir tema
Delete this saved preset Excluir este predefinido salvo
Delete {kind} Style Excluir Estilo de {kind}
Delete the selected items and their artwork? Excluir os itens selecionados e suas ilustrações?
Delete this layer and its artwork? Excluir esta camada e sua ilustração?
Delete “{name}”? Excluir “{name}”?
Depth: Profundidade:
Description Descrição
@@ -4543,6 +4545,7 @@ axis Both Ambos
@msg choose the font files to add escolha os arquivos de fonte a adicionar
@msg not a file não é um arquivo
@msg not a font file não é um arquivo de fonte
@msg the active document changed while the question was open; nothing was deleted o documento ativo mudou enquanto a pergunta estava aberta; nada foi excluído
@msg that document is no longer open esse documento não está mais aberto
@msg larger than 256 MB maior que 256 MB
@msg the files come to more than 1 GB: add fewer at a time os arquivos somam mais de 1 GB: adicione menos por vez
Can't render this file because it contains an unexpected character in line 6 and column 47.
+3
View File
@@ -810,6 +810,8 @@ font-technology Variable Вариативные
Delete Width Point Удалить точку ширины
Delete Workspace Удалить рабочую среду
Delete {kind} Style Удалить стиль {kind}
Delete the selected items and their artwork? Удалить выбранные элементы вместе с графикой?
Delete this layer and its artwork? Удалить этот слой вместе с графикой?
Delete “{name}”? Удалить «{name}»?
Depth: Глубина:
Description Описание
@@ -5131,6 +5133,7 @@ axis Both Оба
@msg choose the font files to add выберите файлы шрифтов для добавления
@msg not a file не файл
@msg not a font file не файл шрифта
@msg the active document changed while the question was open; nothing was deleted активный документ сменился, пока был открыт вопрос; ничего не удалено
@msg that document is no longer open этот документ больше не открыт
@msg larger than 256 MB больше 256 МБ
@msg the files come to more than 1 GB: add fewer at a time файлы занимают больше 1 ГБ: добавляйте меньше за раз
Can't render this file because it is too large.
+3
View File
@@ -799,6 +799,8 @@ font-technology Variable Variabla
Delete Width Point Radera breddpunkt
Delete Workspace Radera arbetslayout
Delete {kind} Style Radera stil ({kind})
Delete the selected items and their artwork? Radera de markerade objekten och deras bildmaterial?
Delete this layer and its artwork? Radera det här lagret och dess bildmaterial?
Delete “{name}”? Radera ”{name}”?
Depth: Djup:
Description Beskrivning
@@ -4989,6 +4991,7 @@ axis Both Båda
@msg choose the font files to add välj de typsnittsfiler som ska läggas till
@msg not a file inte en fil
@msg not a font file inte en typsnittsfil
@msg the active document changed while the question was open; nothing was deleted det aktiva dokumentet ändrades medan frågan var öppen; inget raderades
@msg that document is no longer open det dokumentet är inte längre öppet
@msg larger than 256 MB större än 256 MB
@msg the files come to more than 1 GB: add fewer at a time filerna blir större än 1 GB: lägg till färre åt gången
Can't render this file because it is too large.
+3
View File
@@ -791,6 +791,8 @@ font-technology Variable Değişken
Delete Width Point Genişlik Noktasını Sil
Delete Workspace Çalışma Alanını Sil
Delete {kind} Style {kind} Stilini Sil
Delete the selected items and their artwork? Seçili öğeler ve içlerindeki çizim silinsin mi?
Delete this layer and its artwork? Bu katman ve içindeki çizim silinsin mi?
Delete “{name}”? “{name}” silinsin mi?
Depth: Derinlik:
Description Açıklama
@@ -4827,6 +4829,7 @@ axis Both Her İkisi
@msg choose the font files to add eklenecek yazı tipi dosyalarını seçin
@msg not a file dosya değil
@msg not a font file yazı tipi dosyası değil
@msg the active document changed while the question was open; nothing was deleted soru açıkken etkin belge değişti; hiçbir şey silinmedi
@msg that document is no longer open bu belge artık açık değil
@msg larger than 256 MB 256 MB'tan büyük
@msg the files come to more than 1 GB: add fewer at a time dosyalar 1 GB'tan fazla geliyor: bir kerede daha azını ekleyin
Can't render this file because it contains an unexpected character in line 5 and column 25.
+3
View File
@@ -806,6 +806,8 @@ font-technology Variable Варіативні
Delete Width Point Видалити точку ширини
Delete Workspace Видалити робоче середовище
Delete {kind} Style Видалити стиль {kind}
Delete the selected items and their artwork? Видалити вибрані елементи разом із графікою?
Delete this layer and its artwork? Видалити цей шар разом із графікою?
Delete “{name}”? Видалити "{name}"?
Depth: Глибина:
Description Опис
@@ -5129,6 +5131,7 @@ axis Both Обидві
@msg choose the font files to add виберіть файли шрифтів для додавання
@msg not a file не файл
@msg not a font file не файл шрифту
@msg the active document changed while the question was open; nothing was deleted активний документ змінився, поки питання було відкрите; нічого не видалено
@msg that document is no longer open цей документ більше не відкрито
@msg larger than 256 MB більше 256 МБ
@msg the files come to more than 1 GB: add fewer at a time файли займають понад 1 ГБ: додавайте менше за раз
Can't render this file because it is too large.
+3
View File
@@ -938,6 +938,8 @@ font-technology Variable Biến thiên
Delete Width Point Xóa điểm chiều rộng
Delete Workspace Xóa không gian làm việc
Delete {kind} Style Xóa kiểu {kind}
Delete the selected items and their artwork? Xóa các mục đã chọn và tác phẩm của chúng?
Delete this layer and its artwork? Xóa lớp này và tác phẩm của nó?
Delete “{name}”? Xóa “{name}”?
Depth Độ sâu
Depth: Độ sâu:
@@ -5267,6 +5269,7 @@ theme Appearance Giao diện
@msg t, dx and dy must be finite t, dx và dy phải là số hữu hạn
@msg Targa files are RGB: colorModel rgb Tệp Targa là RGB: colorModel rgb
@msg Text Wrap: select a wrap object Bọc chữ: hãy chọn đối tượng bọc
@msg the active document changed while the question was open; nothing was deleted tài liệu đang hoạt động đã thay đổi khi câu hỏi đang mở; không có gì bị xóa
@msg that document is no longer open tài liệu đó không còn mở
@msg Extrude & Bevel Kéo dài & vát
@msg Revolve Xoay tròn
Can't render this file because it contains an unexpected character in line 204 and column 5.
+3
View File
@@ -755,6 +755,8 @@ antiAlias Sharp 锐利
Delete Width Point 删除宽度点
Delete Workspace 删除工作区
Delete {kind} Style 删除{kind}样式
Delete the selected items and their artwork? 要删除所选项目及其图稿吗?
Delete this layer and its artwork? 要删除此图层及其图稿吗?
Delete “{name}”? 要删除“{name}”吗?
Depth: 深度:
Description 描述
@@ -4897,6 +4899,7 @@ imageTrace Outline 轮廓
@msg choose the font files to add 请选择要添加的字体文件
@msg not a file 不是文件
@msg not a font file 不是字体文件
@msg the active document changed while the question was open; nothing was deleted 问题打开期间活动文档已更改;未删除任何内容
@msg that document is no longer open 该文档已不再打开
@msg larger than 256 MB 大于 256 MB
@msg the files come to more than 1 GB: add fewer at a time 文件总计超过 1 GB:请每次少添加一些
Can't render this file because it contains an unexpected character in line 2 and column 73.
+3
View File
@@ -774,6 +774,8 @@ font-technology Variable 可變
Delete Width Point 刪除寬度點
Delete Workspace 刪除工作區
Delete {kind} Style 刪除{kind}樣式
Delete the selected items and their artwork? 要刪除所選項目及其圖稿嗎?
Delete this layer and its artwork? 要刪除此圖層及其圖稿嗎?
Delete “{name}”? 要刪除「{name}」嗎?
Depth: 深度:
Description 描述
@@ -2664,6 +2666,7 @@ file-filter Templates 範本
@msg choose the font files to add 請選擇要加入的字體檔案
@msg not a file 不是檔案
@msg not a font file 不是字體檔案
@msg the active document changed while the question was open; nothing was deleted 問題開啟期間作用中文件已變更;未刪除任何內容
@msg that document is no longer open 該文件已不再開啟
@msg larger than 256 MB 大於 256 MB
@msg the files come to more than 1 GB: add fewer at a time 檔案總計超過 1 GB:請每次少加入一些
Can't render this file because it contains an unexpected character in line 6 and column 47.
+1
View File
@@ -829,6 +829,7 @@ fn run_ui_part8(app: &mut VectorcraftApp, id: &str, p: &Value) -> Option<Result<
}
"ui.tileEdgeColor" => crate::dialogs::tile_edge_color::open(app),
"ui.layerOptions" => crate::dialogs::layer_options::open(app, p),
"ui.layerDelete" => crate::panels::layers::delete(app, p),
"ui.rename" => crate::panels::layers::rename(app, p),
"ui.newLayer" => crate::dialogs::layer_options::open_new(app, p),
"ui.newArtboard" => crate::dialogs::artboard_options::open_new(app),
+6
View File
@@ -946,6 +946,12 @@ pub const UI_COMMANDS: &[(&str, &str, &str, &str)] = &[
"",
"{ids?|id?} open Layer Options for Layers panel rows (default: the highlighted rows, else the current layer), filled in from the first: dialog `layerOptions`, fields name, color (a preset name such as \"Light Blue\" or #rrggbb), template, locked, visible, printable, preview, dimImages (bool), dimPercent (0–100); an object's row has name, visible and locked. OK runs layer.setProps (one undo step); for several rows it sends only the fields set in the dialog",
),
(
"ui.layerDelete",
"Delete Selection",
"",
"{ids?|id?, doc?, confirmed?: bool} Delete Selection as the Layers panel runs it (its trash button, rows dropped on the trash, its menu, Delete and Backspace), on the rows layer.delete takes (default: the highlighted rows, else the current layer). When a layer or sublayer among them holds art (an object other than a guide; hidden, locked and nested objects count) it asks first: dialog `confirm` with `message`; OK deletes those rows by id with layer.delete (one undo step), Cancel keeps them. OK runs ui.layerDelete again with the rows, `doc` (the document's uid) and `confirmed: true`: with another document active then, nothing is deleted. Other rows (an empty layer, groups and objects alone) and rows layer.delete refuses go to layer.delete at once → layer.delete's {deleted}, or null while the question is open",
),
(
"ui.rename",
"Rename",
+4 -2
View File
@@ -22,6 +22,8 @@
//! a box shows where); Alt copies them. A dimmed copy of the row follows the pointer. Layers
//! dropped in the empty space under the last row go below the bottom layer. Dropped on the trash
//! they are deleted, on New Layer duplicated.
//! - Deleting rows from the panel (the trash, rows dropped on it, Delete Selection, Delete and
//! Backspace) asks first when a layer or sublayer among them holds art ([`delete`]).
//! - The triangle opens or closes a row; Alt-click does the same to everything inside it.
//! - Double-clicking a name renames it; double-clicking elsewhere on a row opens its options.
//! - A target circle targets its layer, group or object (`layer.target`); dragging it onto another
@@ -60,7 +62,7 @@ mod rows;
mod thumbs;
use controls::{bottom_bar, filter_button};
pub use controls::{expand, menu, set_filter};
pub use controls::{delete, expand, menu, set_filter};
pub(crate) use model::shown_name;
pub use model::{Filter, ObjectKind, RowState};
#[cfg(test)]
@@ -381,7 +383,7 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
&& ui.ctx().memory(|m| m.focused().is_none())
&& ui.input_mut(|i| i.consume_key(egui::Modifiers::NONE, egui::Key::Delete) || i.consume_key(egui::Modifiers::NONE, egui::Key::Backspace))
{
out.actions.push(("layer.delete".into(), json!({})));
out.actions.push(("ui.layerDelete".into(), json!({})));
}
bottom_bar(app, ui, &view, &doc, &mut out.actions);
for (c, p) in out.actions {
+71 -5
View File
@@ -1,6 +1,6 @@
use super::model::{ObjectKind, RowState, names, parse_names, toggled};
use super::{
Document, HashSet, LayersDrag, Node, NodeId, NodeKind, PanelDrag, Sense, Stroke, Ui, Value, VectorcraftApp, View, json, last_selected,
Arc, Document, HashSet, LayersDrag, Node, NodeId, NodeKind, PanelDrag, Sense, Stroke, Ui, Value, VectorcraftApp, View, json, last_selected,
see_selection, vec2, widgets,
};
@@ -66,7 +66,7 @@ pub(super) fn bottom_bar(app: &mut VectorcraftApp, ui: &mut Ui, view: &View, doc
if view.rows.is_empty() && app.session.active().is_some_and(|d| !d.selection.is_empty()) {
actions.push(("edit.clear".into(), json!({})));
} else {
actions.push(("layer.delete".into(), json!({})));
actions.push(("ui.layerDelete".into(), json!({})));
}
}
// Create New Layer: Alt asks for its options first, Ctrl/Cmd puts it on top of every layer,
@@ -83,14 +83,14 @@ pub(super) fn bottom_bar(app: &mut VectorcraftApp, ui: &mut Ui, view: &View, doc
}
// Rows dropped on the trash are deleted, on New Layer duplicated, as in Illustrator. Both are
// outlined while rows (or, on the trash, a target circle) hang over them.
for (button, cmd) in [(&trash, "layer.delete"), (&new_layer, "layer.duplicate")] {
for (button, cmd) in [(&trash, "ui.layerDelete"), (&new_layer, "layer.duplicate")] {
if let Some(d) = button.dnd_release_payload::<LayersDrag>()
&& let LayersDrag::Rows(ids) = &*d
{
actions.push((cmd.into(), json!({"ids": ids.iter().map(|i| i.0).collect::<Vec<_>>()})));
}
let over = button.dnd_hover_payload::<LayersDrag>().is_some_and(|d| matches!(*d, LayersDrag::Rows(_)))
|| (cmd == "layer.delete" && button.dnd_hover_payload::<PanelDrag>().is_some_and(|d| matches!(*d, PanelDrag::Appearance(_))));
|| (cmd == "ui.layerDelete" && button.dnd_hover_payload::<PanelDrag>().is_some_and(|d| matches!(*d, PanelDrag::Appearance(_))));
if over {
widgets::drop_target_outline(&child, button.rect);
}
@@ -143,7 +143,7 @@ pub fn menu(app: &mut VectorcraftApp, ui: &mut Ui) {
Some(("New Layer…", "ui.newLayer", json!({}), true, false)),
Some(("New Sublayer…", "ui.newLayer", json!({"sublayer": true}), current.is_some(), false)),
Some(("Duplicate Selection", "layer.duplicate", json!({}), !targets.is_empty(), false)),
Some(("Delete Selection", "layer.delete", json!({}), !targets.is_empty(), false)),
Some(("Delete Selection", "ui.layerDelete", json!({}), !targets.is_empty(), false)),
Some(("Options for Selection…", "ui.layerOptions", json!({}), !targets.is_empty(), false)),
None,
Some(("Make/Release Clipping Mask", "layer.clippingMask.toggle", json!({}), true, false)),
@@ -272,6 +272,72 @@ fn save_selection_menu(app: &mut VectorcraftApp, ui: &mut Ui) {
});
}
/// `ui.layerDelete {ids?|id?, doc?, confirmed?}`: Delete Selection as the Layers panel runs it (the
/// trash button, rows dropped on it, the panel menu, Delete and Backspace), on the rows
/// `layer.delete` takes. When a layer or sublayer among them holds art (an object other than a
/// guide, hidden, locked and nested ones included), it asks first: OK deletes those rows, by id, in
/// the same document (`doc`, its uid, with `confirmed`); with another document active then, nothing
/// is deleted. Other rows, and rows `layer.delete` refuses (an unknown id, every top-level layer),
/// go to `layer.delete` at once. → `layer.delete`'s result, or null while the question is open
pub fn delete(app: &mut VectorcraftApp, p: &Value) -> Result<Value, String> {
let confirmed = crate::menus::opt_bool(p, "confirmed")?.unwrap_or(false);
let key = "doc";
let doc = match p.get(key) {
None | Some(Value::Null) => None,
Some(v) => Some(v.as_u64().ok_or_else(|| format!("`{key}` must be a whole number of 0 or more"))?),
};
let st = app.session.active().ok_or("no document open")?;
if doc.is_some_and(|d| d != st.uid) {
return Err("the active document changed while the question was open; nothing was deleted".into());
}
let rows: serde_json::Map<String, Value> = ["ids", "id"].iter().filter_map(|k| Some((k.to_string(), p.get(*k)?.clone()))).collect();
// An id the engine refuses: `layer.delete` gives the error, and deletes nothing.
let row = |v: &Value| v.as_u64().map(NodeId).filter(|id| st.doc.node(*id).is_some_and(|n| !n.is_ruler_guide()));
let ids: Option<Vec<NodeId>> = match (p.get("ids"), p.get("id")) {
(Some(v), _) => v.as_array().and_then(|a| a.iter().map(row).collect()),
(None, Some(v)) => row(v).map(|id| vec![id]),
(None, None) => {
let rows = st.highlighted_rows();
Some(if rows.is_empty() { st.current_layer().into_iter().collect() } else { rows })
}
};
let Some(ids) = ids.filter(|_| !confirmed) else { return app.run("layer.delete", Value::Object(rows)) };
let listed: HashSet<NodeId> = ids.iter().copied().collect();
let mut roots = vec![];
row_roots(&st.doc.layers, &listed, &mut roots);
let every_layer = st.doc.layers.iter().all(|l| listed.contains(&l.id));
if every_layer || !roots.iter().any(|n| n.is_layer() && holds_art(n)) {
return app.run("layer.delete", json!({ "ids": ids.iter().map(|i| i.0).collect::<Vec<_>>() }));
}
let message = match roots.as_slice() {
[n] if n.is_layer() => tl!("Delete this layer and its artwork?"),
_ => tl!("Delete the selected items and their artwork?"),
};
let params = json!({"ids": ids.iter().map(|i| i.0).collect::<Vec<_>>(), "doc": st.uid, "confirmed": true});
crate::dialogs::confirm::ask(app, message, "", "ui.layerDelete", params);
Ok(Value::Null)
}
/// The rows among `nodes` (and the rows inside them) that are in `listed` and not inside another
/// listed row, top-level first.
fn row_roots<'a>(nodes: &'a [Arc<Node>], listed: &HashSet<NodeId>, out: &mut Vec<&'a Node>) {
for n in nodes {
if out.len() == listed.len() {
return;
}
if listed.contains(&n.id) {
out.push(n);
} else if let Some(children) = n.children() {
row_roots(children, listed, out);
}
}
}
/// Whether a layer holds art: an object other than a guide, in it or in one of its sublayers.
fn holds_art(layer: &Node) -> bool {
layer.children().into_iter().flatten().any(|c| if c.is_layer() { holds_art(c) } else { !c.is_guide() })
}
/// `ui.layersExpand {ids?, open?}`: open (or close) rows of the active document's Layers panel;
/// without `ids`, every row that holds others.
pub fn expand(app: &mut VectorcraftApp, p: &Value) -> Result<Value, String> {
+124 -1
View File
@@ -452,6 +452,127 @@ fn dragging_rows_onto_the_trash_deletes_them() {
assert!(doc.node(top).is_none());
}
/// The message of the confirmation open now, if one is.
fn asked(app: &VectorcraftApp) -> Option<String> {
app.ui.dialog.as_ref().filter(|d| d.kind == crate::dialogs::confirm::KIND).map(|d| d.str("message"))
}
/// The trash, the Delete key and rows dropped on the trash ask before deleting a layer that holds
/// art, hidden and locked art included: Cancel keeps it, and OK deletes the rows it asked about in
/// one undo step, even after another row was highlighted.
#[test]
fn deleting_a_layer_that_holds_art_asks_first() {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
let run = |app: &mut VectorcraftApp, id: &str, p: serde_json::Value| app.session.execute(id, &p).unwrap();
run(&mut app, "file.new", json!({"width": 200, "height": 200}));
let rect = NodeId(run(&mut app, "shape.rectangle", json!({"x": 0, "y": 0, "width": 20, "height": 20}))["id"].as_u64().unwrap());
run(&mut app, "select.none", json!({}));
run(&mut app, "layer.setProps", json!({"ids": [rect.0], "visible": false, "locked": true}));
let art = app.session.active().unwrap().doc.layers[0].id;
run(&mut app, "layer.new", json!({}));
let there = |app: &VectorcraftApp| app.session.active().unwrap().doc.node(art).is_some();
let ctx = egui::Context::default();
// Rows top first: Layer 2, Layer 1, its rectangle.
let (c, _) = frame(&mut app, &ctx, vec![], false);
let name = |i: usize| egui::pos2(150.0, c[i].y);
let question = Some("Delete this layer and its artwork?".to_string());
click_with(&mut app, &ctx, name(1), egui::Modifiers::NONE);
let trash = trash_pos(&mut app, &ctx);
click_with(&mut app, &ctx, trash, egui::Modifiers::NONE);
assert_eq!(asked(&app), question, "the trash asks");
assert!(there(&app), "nothing is deleted before OK");
crate::dialogs::cancel(&mut app);
assert!(app.ui.dialog.is_none() && there(&app), "Cancel keeps the layer");
click_with(&mut app, &ctx, name(1), egui::Modifiers::NONE);
let del = egui::Event::Key { key: egui::Key::Delete, physical_key: None, pressed: true, repeat: false, modifiers: egui::Modifiers::NONE };
frame(&mut app, &ctx, vec![del], false);
assert_eq!(asked(&app), question, "Delete asks");
assert!(there(&app));
crate::dialogs::cancel(&mut app);
let undo = app.session.active().unwrap().history.undo.len();
drag(&mut app, &ctx, c[1] - vec2(100.0, 0.0), trash, false);
assert_eq!(asked(&app), question, "a drop on the trash asks");
assert!(there(&app));
// Highlighting Layer 2 now leaves OK deleting the row that was dropped.
click_with(&mut app, &ctx, name(0), egui::Modifiers::NONE);
crate::dialogs::confirm(&mut app).unwrap();
let st = app.session.active().unwrap();
assert!(app.ui.dialog.is_none() && st.doc.node(art).is_none() && st.doc.node(rect).is_none());
assert_eq!((st.doc.layers.len(), st.history.undo.len()), (1, undo + 1), "one undo step");
run(&mut app, "edit.undo", json!({}));
assert!(there(&app));
}
/// The panel menu's Delete Selection (`ui.layerDelete`) asks once for several rows when one of
/// them is a layer with art, art in a sublayer included; an empty layer, a layer with only a
/// guide, and objects alone go at once, and `layer.delete` itself never asks.
#[test]
fn delete_selection_asks_only_for_layers_with_art() {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
let run = |app: &mut VectorcraftApp, id: &str, p: serde_json::Value| app.session.execute(id, &p).unwrap();
let id = |v: serde_json::Value| v["id"].as_u64().unwrap();
run(&mut app, "file.new", json!({"width": 200, "height": 200}));
let bottom = app.session.active().unwrap().doc.layers[0].id.0;
let loose = id(run(&mut app, "shape.rectangle", json!({"x": 0, "y": 0, "width": 20, "height": 20})));
let outer = id(run(&mut app, "layer.new", json!({})));
let sub = id(run(&mut app, "layer.newSublayer", json!({})));
let nested = id(run(&mut app, "shape.ellipse", json!({"x": 50, "y": 50, "width": 20, "height": 20})));
run(&mut app, "select.none", json!({}));
let empty = id(run(&mut app, "layer.new", json!({"top": true})));
let guided = id(run(&mut app, "layer.new", json!({"top": true})));
run(&mut app, "guide.add", json!({"vertical": true, "pos": 50, "layer": guided}));
run(&mut app, "select.none", json!({}));
let exists = |app: &VectorcraftApp, id: u64| app.session.active().unwrap().doc.node(NodeId(id)).is_some();
for (rows, what) in [(json!([empty]), "an empty layer"), (json!([guided]), "a layer with only a guide"), (json!([loose]), "an object")] {
app.run("ui.layerDelete", json!({ "ids": rows })).unwrap();
assert!(app.ui.dialog.is_none(), "{what} goes at once");
assert!(!exists(&app, rows[0].as_u64().unwrap()), "{what} is deleted");
}
run(&mut app, "edit.undo", json!({}));
// Art in a sublayer counts; the highlighted rows are the default, and a mixed selection asks once.
run(&mut app, "layer.highlight", json!({"ids": [outer, loose]}));
app.run("ui.layerDelete", json!({})).unwrap();
assert_eq!(asked(&app).as_deref(), Some("Delete the selected items and their artwork?"));
assert!(exists(&app, nested) && exists(&app, loose));
crate::dialogs::confirm(&mut app).unwrap();
assert!(!exists(&app, outer) && !exists(&app, sub) && !exists(&app, nested) && !exists(&app, loose));
assert!(app.ui.dialog.is_none(), "asked once");
// A sublayer with art asks as a layer does.
run(&mut app, "edit.undo", json!({}));
app.run("ui.layerDelete", json!({ "id": sub })).unwrap();
assert_eq!(asked(&app).as_deref(), Some("Delete this layer and its artwork?"));
crate::dialogs::cancel(&mut app);
// Scripts deleting with layer.delete are not asked.
app.run("layer.delete", json!({ "ids": [outer] })).unwrap();
assert!(app.ui.dialog.is_none() && !exists(&app, outer));
assert!(exists(&app, bottom));
}
/// Rows `layer.delete` refuses are refused without a question, and OK deletes nothing once another
/// document is active.
#[test]
fn delete_selection_refusals_and_a_document_change() {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
let run = |app: &mut VectorcraftApp, id: &str, p: serde_json::Value| app.session.execute(id, &p).unwrap();
run(&mut app, "file.new", json!({"width": 200, "height": 200}));
run(&mut app, "shape.rectangle", json!({"x": 0, "y": 0, "width": 20, "height": 20}));
let only = app.session.active().unwrap().doc.layers[0].id.0;
let e = app.run("ui.layerDelete", json!({ "ids": [only] })).unwrap_err();
assert!(e.contains("at least one layer") && app.ui.dialog.is_none(), "{e}");
for bad in [json!({"ids": [999_999]}), json!({"id": "x"}), json!({"ids": 3}), json!({"confirmed": "yes"}), json!({"doc": -1})] {
assert!(app.run("ui.layerDelete", bad.clone()).is_err() && app.ui.dialog.is_none(), "{bad}");
}
let art = run(&mut app, "layer.new", json!({}))["id"].as_u64().unwrap();
run(&mut app, "shape.rectangle", json!({"x": 0, "y": 0, "width": 20, "height": 20}));
app.run("ui.layerDelete", json!({ "ids": [art] })).unwrap();
assert!(asked(&app).is_some());
run(&mut app, "file.new", json!({"width": 100, "height": 100}));
let e = crate::dialogs::confirm(&mut app).unwrap_err();
assert!(e.contains("nothing was deleted"), "{e}");
let first = &app.session.documents()[0].doc;
assert!(first.node(NodeId(art)).is_some(), "the first document keeps the layer");
}
#[test]
fn renaming_a_layer_commits_on_enter_and_escape_cancels() {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
@@ -665,9 +786,11 @@ fn rows_at_every_depth_are_clickable() {
assert_eq!(rows_of(&app), vec![sub, b, a]);
click_with(&mut app, &ctx, name(5), egui::Modifiers::COMMAND);
assert_eq!(rows_of(&app), vec![sub, b, a, c]);
// Delete with the panel's keyboard: the highlighted rows go.
// Delete with the panel's keyboard: the highlighted rows go once OK answers the question the
// sublayer's art asks.
let del = egui::Event::Key { key: egui::Key::Delete, physical_key: None, pressed: true, repeat: false, modifiers: egui::Modifiers::NONE };
frame(&mut app, &ctx, vec![del], false);
crate::dialogs::confirm(&mut app).unwrap();
let d = &app.session.active().unwrap().doc;
assert!(d.node(sub).is_none() && d.node(c).is_none());
assert_eq!(d.layers.len(), 1);
+3
View File
@@ -140,6 +140,9 @@ of another kind, it moves.
Confirmations: deleting swatches from the Swatches panel opens a `confirm` dialog (fields `message`, `detail`);
`ui.dialog.confirm` runs the command it asks about (here `swatch.delete`) and `ui.dialog.cancel` drops it.
Deleting Layers panel rows that include a layer or sublayer with art (`engine.execute` of `ui.layerDelete`, which the
panel's trash, its menu's Delete Selection and Delete or Backspace run) opens a `confirm` dialog too; its OK deletes
those rows with `layer.delete` in the document the question was asked in. `layer.delete` itself deletes at once.
New swatches and colour groups: `ui.newSwatch {spot?, global?, group?}` opens the `newSwatch` dialog prefilled from the active
fill or stroke (fields as in `swatchOptions` plus `group`; a gradient or pattern only takes `name`) and
+6 -1
View File
@@ -4273,7 +4273,12 @@ and `layerRows`, the rows highlighted in the panel.
`layer.newSublayer {parent?, bottom?, name?, …options}` (on top of the parent's contents; `bottom`, under them but
above a clipping layer's clipping path, with Ctrl/Cmd+Alt; both refused while an opacity mask is edited),
`layer.delete {ids?}` (rows with what they hold; the
last layer stays), `layer.locate {id?}` (highlights the selected object's row; the panel opens the rows around it)
last layer stays; it does not ask), `ui.layerDelete {ids?|id?}` (the panel's trash, rows dropped on it, Delete
Selection, and Delete or Backspace on highlighted rows: when a layer or sublayer among the rows holds art, hidden,
locked or nested art included, dialog `confirm` asks "Delete this layer and its artwork?" for one layer, else "Delete
the selected items and their artwork?"; OK deletes the rows it asked about in that document, one undo step, and
Cancel keeps them; an empty layer, a layer with only guides, and groups or objects alone are deleted at once),
`layer.locate {id?}` (highlights the selected object's row; the panel opens the rows around it)
and `layer.clippingMask.toggle`.
- **Panel menu**: `layer.duplicate {ids?}`, `layer.merge {ids?}` (into the layer highlighted last, keeping the
stacking order), `layer.flatten {id?}` (every other visible layer's art into one layer; hidden layers are deleted,
+1
View File
@@ -1099,6 +1099,7 @@ Moved from the ROADMAP's "Shipped so far" on 2026-10-10. Update it when a featur
- **Layers panel:** every layer, sublayer, group and object is a clickable row at any depth: a click highlights it and makes its layer current (new art goes there), Shift-click a range, Ctrl/Cmd-click toggles. Sublayers are no longer treated as objects: clicks, marquees, Select All and the Select menu take the art inside them, and each sublayer selects in its own colour. Selection squares on rows with selected art (click selects a row's art, Shift adds or removes; dragging the square moves the selection to another row, Alt copies), the eye and lock on every row with drag-down-the-column (one undo step), Ctrl/Cmd-click an eye for per-layer Outline, Alt-click an eye or lock to hide or lock the other layers (again: show or unlock them all), triangles with Alt to open or close everything inside, drag and drop rows above, below or into layers and groups with a drop line (Alt copies) and a dimmed copy of the row under the pointer (layers dropped in the empty space under the last row go below the bottom layer, #2260; dropped on the trash rows are deleted, on New Layer duplicated, as in Illustrator), inline rename, Delete key on highlighted rows. Buttons and the full panel menu: New Layer/Sublayer (Alt: options, Ctrl: on top), Duplicate, Delete, Options for Selection, clipping mask, isolation, Locate Object, Merge Selected, Flatten Artwork, Collect in New Layer, Release to Layers (Sequence and Build), Reverse Order, Template, Hide/Outline/Lock Others and Show/Preview/Unlock All, Paste Remembers Layers, Panel Options (row size, thumbnails per kind, Show Layers Only). Layer Options: name, colour (presets, each with a chip of its colour, or custom), Template, Lock, Show, Print, Preview (outline drawing and clicking) and Dim Images to %. Every operation is a command (`layer.move`, `layer.highlight`, `layer.merge`…) with validation against cycles and invalid nesting. A document opens with only its top-level layers open; the rows left open are saved in the native file (nothing is written for the default) and reopen that way. Only the rows scrolled into view are laid out, from a row list made once per change: a layer of 5,000 groups of 10 paths, all open, draws the panel in 0.4 ms a frame instead of about 29 s (#638).
The Filter button at the right of Search All keeps the rows that are of an object kind ticked under By Object (paths, shapes, text, images, effects, groups, linked files, guides) and in a state ticked under By Layer (locked, hidden), with the rows that hold them; a section with nothing ticked takes every row. The filter combines with the search, the button is lit while a filter is on, and Clear All in its popup turns the filter off (`ui.layersFilter`). The filter lasts the session.
The panel menu's Save Selection submenu has Save Selection…, Update Selection and Edit Selection…, enabled and run as in the Select menu, and lists the document's saved selections: choosing one selects its objects again (`select.recall`).
Deleting rows from the Layers panel (the trash button, rows dragged onto it, the panel menu's Delete Selection, and Delete or Backspace on highlighted rows) asks "Delete this layer and its artwork?" when a layer or sublayer among them holds art, hidden, locked and nested art included, and "Delete the selected items and their artwork?" when several rows are deleted; OK deletes the rows it asked about in one undo step, and Cancel keeps them (`ui.layerDelete`). The help page's shortcut list names the Layers panel as the place where deleting asks for confirmation ([Default keyboard shortcuts](https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html)). An empty layer, a layer with only guides, and groups or objects alone are deleted without a question, and `layer.delete` itself does not ask (`panels::layers` tests `deleting_a_layer_that_holds_art_asks_first`, `delete_selection_asks_only_for_layers_with_art`).
`object.setProps` with `visible: false` or `locked: true` deselects every selected object that is then hidden or locked, the key object included, as the eye and lock columns do.
Ctrl/Cmd+Alt-clicking an eye switches the other layers to Outline and the row's layer to Preview, or switches all layers back to Preview when the others are in Outline (`layer.outlineOthers`, `layer.previewAll`).
Ctrl/Cmd+Alt-clicking New Layer adds a layer directly below the current layer, at its level (`layer.new {below: true}`), and Ctrl/Cmd+Alt-clicking New Sublayer adds a sublayer under the contents of the layer it goes into (`layer.newSublayer {bottom: true}`), each in one undo step. The reference app's [Default keyboard shortcuts](https://web.archive.org/web/20260726060015/https://helpx.adobe.com/illustrator/using/default-keyboard-shortcuts.html) page lists these clicks for placing a layer below the selected layer and a new sublayer at the bottom of the layer list.