mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-10-27 11:37:59 -06:00
Merge PR #2731: Layers panel: Reset to Initial Visibility
Conflicts: - ATTRIBUTION.toml: ours (sha256 lines only); hashes recomputed at the end of the track - crates/engine/Cargo.toml: main's workspace chrono entry, plus the PR's pdfcraft-testkit dev-dependency
This commit is contained in:
Generated
+1
@@ -4134,6 +4134,7 @@ dependencies = [
|
||||
"pdfcraft-redact",
|
||||
"pdfcraft-render",
|
||||
"pdfcraft-sign",
|
||||
"pdfcraft-testkit",
|
||||
"pdfcraft-xfa",
|
||||
"pdfcraft-xfdf",
|
||||
"png 0.18.1",
|
||||
|
||||
@@ -2473,7 +2473,7 @@ fn info(d: &Document) -> Value {
|
||||
pdfcraft_render::LinkTarget::Other(o) => json!({ "other": o }),
|
||||
},
|
||||
})).collect::<Vec<_>>(),
|
||||
"layers": i.layers.iter().map(|l| json!({ "name": l.name, "visible": l.visible })).collect::<Vec<_>>(),
|
||||
"layers": i.layers.iter().map(|l| json!({ "name": l.name, "visible": l.visible, "initial": l.initial })).collect::<Vec<_>>(),
|
||||
// Full-screen presentation settings a page carries (ISO 32000-2 §12.4.4): only pages with
|
||||
// a `/Trans` or `/Dur` appear; `style` is null for a display time alone.
|
||||
"transitions": i.transitions.iter().map(|t| json!({
|
||||
|
||||
@@ -5832,12 +5832,13 @@ fn doc_info_says_when_a_runaway_script_turned_the_forms_scripts_off() {
|
||||
let _ = std::fs::remove_dir_all(dir);
|
||||
}
|
||||
|
||||
/// doc_info describes a link's set-layer-visibility action by layer name.
|
||||
/// doc_info describes a link's set-layer-visibility action by layer name, and each layer's
|
||||
/// visibility now and as the file opens.
|
||||
#[test]
|
||||
fn doc_info_describes_set_layer_links() {
|
||||
let dir = workdir("layer-links");
|
||||
let objs = [
|
||||
"<< /Type /Catalog /Pages 2 0 R /OCProperties << /OCGs [4 0 R 5 0 R] /D << >> >> >>",
|
||||
"<< /Type /Catalog /Pages 2 0 R /OCProperties << /OCGs [4 0 R 5 0 R] /D << /OFF [5 0 R] >> >> >>",
|
||||
"<< /Type /Pages /Kids [3 0 R] /Count 1 >>",
|
||||
"<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] /Annots [6 0 R] >>",
|
||||
"<< /Type /OCG /Name (Red) >>",
|
||||
@@ -5868,6 +5869,7 @@ fn doc_info_describes_set_layer_links() {
|
||||
"preserve_rb": false,
|
||||
})
|
||||
);
|
||||
assert_eq!(info["layers"], json!([{ "name": "Red", "visible": true, "initial": true }, { "name": "Green", "visible": false, "initial": false }]));
|
||||
}
|
||||
|
||||
mod close_argument_tests {
|
||||
|
||||
@@ -51,3 +51,6 @@ unicode-segmentation = "1.13"
|
||||
# Already in the graph through lopdf; used only for the local UTC offset ("today"). The workspace
|
||||
# entry is std-only; this target adds `clock` for `chrono::Local::now`.
|
||||
chrono = { workspace = true, features = ["clock"] }
|
||||
|
||||
[dev-dependencies]
|
||||
pdfcraft-testkit = { workspace = true }
|
||||
|
||||
@@ -4819,6 +4819,22 @@ impl Session {
|
||||
true
|
||||
}
|
||||
|
||||
/// Show each layer as the file opens (Acrobat's Layers ▸ Reset to Initial Visibility). Returns
|
||||
/// `true` if any layer changed; callers must drop cached rasters and text for the document,
|
||||
/// as for [`Self::set_layer_visible`].
|
||||
pub fn reset_layers(&mut self, id: DocId) -> bool {
|
||||
let Some(doc) = self.docs.iter_mut().find(|d| d.id == id) else { return false };
|
||||
let mut changed = false;
|
||||
for l in &mut doc.info.layers {
|
||||
changed |= l.visible != l.initial;
|
||||
l.visible = l.initial;
|
||||
}
|
||||
if changed {
|
||||
use_layer_choices(doc);
|
||||
}
|
||||
changed
|
||||
}
|
||||
|
||||
/// Hide or show every comment on the page (Acrobat's Comments ▸ Hide all comments). Form
|
||||
/// fields and links still draw. Returns whether anything changed.
|
||||
pub fn set_hide_comments(&mut self, id: DocId, hide: bool) -> bool {
|
||||
|
||||
@@ -685,7 +685,7 @@ fn layer_choices_survive_edits() {
|
||||
#[test]
|
||||
fn set_layer_actions_toggle_in_order_and_keep_radio_groups() {
|
||||
use pdfcraft_render::LayerOp::{Off, On, Toggle};
|
||||
let layer = |n: u32, visible: bool| Layer { id: (n, 0), name: format!("L{n}"), visible };
|
||||
let layer = |n: u32, visible: bool| Layer { id: (n, 0), name: format!("L{n}"), visible, initial: visible };
|
||||
let run = |changes: &[(LayerOp, u32)], preserve_rb: bool| {
|
||||
// L1 and L2 are a radio-button group; L3 is on its own.
|
||||
let mut layers = vec![layer(1, true), layer(2, false), layer(3, true)];
|
||||
@@ -761,6 +761,59 @@ fn set_layer_actions_change_what_renders() {
|
||||
assert!(!s.set_layer_state(DocId(999), &[(LayerOp::On, (5, 0))], true));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_layers_returns_to_the_files_visibility() {
|
||||
// Red (left half, on) and Green (right half, off) are a radio-button group.
|
||||
let content = "/OC /R BDC 1 0 0 rg 0 0 50 100 re f EMC /OC /G BDC 0 1 0 rg 50 0 50 100 re f EMC";
|
||||
let pdf = pdfcraft_testkit::Pdf::new()
|
||||
.obj("<< /Type /Catalog /Pages 2 0 R /OCProperties << /OCGs [5 0 R 6 0 R] /D << /OFF [6 0 R] /RBGroups [[5 0 R 6 0 R]] >> >> >>")
|
||||
.obj("<< /Type /Pages /Kids [3 0 R] /Count 1 >>")
|
||||
.obj("<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Contents 4 0 R /Resources << /Properties << /R 5 0 R /G 6 0 R >> >> >>")
|
||||
.stream("", content)
|
||||
.obj("<< /Type /OCG /Name (Red) >>")
|
||||
.obj("<< /Type /OCG /Name (Green) >>")
|
||||
.build();
|
||||
// A page drawing on layer Blue, which that file has off.
|
||||
let other = pdfcraft_testkit::Pdf::new()
|
||||
.obj("<< /Type /Catalog /Pages 2 0 R /OCProperties << /OCGs [5 0 R] /D << /OFF [5 0 R] >> >> >>")
|
||||
.obj("<< /Type /Pages /Kids [3 0 R] /Count 1 >>")
|
||||
.obj("<< /Type /Page /Parent 2 0 R /MediaBox [0 0 100 100] /Contents 4 0 R /Resources << /Properties << /B 5 0 R >> >> >>")
|
||||
.stream("", "/OC /B BDC 0 0 1 rg 0 0 10 10 re f EMC")
|
||||
.obj("<< /Type /OCG /Name (Blue) >>")
|
||||
.build();
|
||||
let mut s = Session::new();
|
||||
let id = s.open("layers.pdf", None, Arc::new(pdf), None).unwrap();
|
||||
let shown = |s: &Session| s.get(id).unwrap().info.layers.iter().map(|l| (l.name.clone(), l.visible)).collect::<Vec<_>>();
|
||||
let left = |s: &Session| {
|
||||
let doc = s.get(id).unwrap();
|
||||
let mut r = pdfcraft_render::PageRenderer::new(doc.bytes.clone(), doc.config.clone());
|
||||
let p = r.render(pdfcraft_render::RenderRequest { page: 0, kind: pdfcraft_render::RequestKind::Pixels, scale: 1.0, ..Default::default() });
|
||||
let i = (50 * p.width as usize + 25) * 4;
|
||||
p.rgba[i..i + 3].to_vec()
|
||||
};
|
||||
assert!(s.set_layer_state(id, &[(LayerOp::On, (6, 0))], true));
|
||||
let edit = Edit::InsertPagesFrom {
|
||||
name: "b.pdf".into(),
|
||||
bytes: Arc::new(other),
|
||||
pages: None,
|
||||
at: 1,
|
||||
field_conflicts: pdfcraft_organize::FieldConflicts::Rename,
|
||||
};
|
||||
s.apply(id, edit).unwrap();
|
||||
let blue = s.get(id).unwrap().info.layers.iter().position(|l| l.name == "Blue").unwrap();
|
||||
assert!(s.set_layer_visible(id, blue, true));
|
||||
assert_eq!(shown(&s), [("Red".into(), false), ("Green".into(), true), ("Blue".into(), true)]);
|
||||
assert_eq!(left(&s), [255, 255, 255]);
|
||||
// Every layer, the inserted one too, goes back to the file's default configuration.
|
||||
assert!(s.reset_layers(id));
|
||||
assert_eq!(shown(&s), [("Red".into(), true), ("Green".into(), false), ("Blue".into(), false)]);
|
||||
assert_eq!(left(&s), [255, 0, 0]);
|
||||
assert!(!s.reset_layers(id), "already as the file opens");
|
||||
// What the eye sees is not an edit: Undo still undoes the insert.
|
||||
assert_eq!(s.get(id).unwrap().can_undo(), Some("Insert pages from b.pdf"));
|
||||
assert!(!s.reset_layers(DocId(999)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn edits_to_unknown_documents_are_rejected() {
|
||||
let (mut s, _) = session_with(1);
|
||||
|
||||
@@ -425,6 +425,8 @@ pub struct Layer {
|
||||
pub id: (u32, u16),
|
||||
pub name: String,
|
||||
pub visible: bool,
|
||||
/// Shown as the file opens: the default configuration (`/OCProperties /D`).
|
||||
pub initial: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -1428,7 +1430,7 @@ impl<'a> Inspector<'a> {
|
||||
_ => !base_off,
|
||||
};
|
||||
let Some(id) = id else { continue };
|
||||
out.push(Layer { id, name: self.text(d, b"Name").unwrap_or_else(|| "Layer".into()), visible });
|
||||
out.push(Layer { id, name: self.text(d, b"Name").unwrap_or_else(|| "Layer".into()), visible, initial: visible });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2358,6 +2360,24 @@ trailer << /Root 1 0 R /Info 4 0 R >>
|
||||
assert_eq!(info.layer_groups, [vec![(5, 0), (6, 0)], vec![(6, 0), (7, 0)]]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn initial_layer_visibility_is_the_default_configuration() {
|
||||
// BaseState OFF: Red is listed ON; Green is listed both ON and OFF, and OFF wins; Blue
|
||||
// isn't listed, so it takes the base state.
|
||||
let pdf = b"%PDF-1.7
|
||||
1 0 obj << /Type /Catalog /Pages 2 0 R /OCProperties << /OCGs [5 0 R 6 0 R 7 0 R] /D << /BaseState /OFF /ON [5 0 R 6 0 R] /OFF [6 0 R] >> >> >> endobj
|
||||
2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj
|
||||
3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] >> endobj
|
||||
5 0 obj << /Type /OCG /Name (Red) >> endobj
|
||||
6 0 obj << /Type /OCG /Name (Green) >> endobj
|
||||
7 0 obj << /Type /OCG /Name (Blue) >> endobj
|
||||
trailer << /Root 1 0 R >>
|
||||
%%EOF";
|
||||
let info = inspect(Arc::new(pdf.to_vec()), None).expect("opens");
|
||||
let layers: Vec<_> = info.layers.iter().map(|l| (l.name.as_str(), l.initial)).collect();
|
||||
assert_eq!(layers, [("Red", true), ("Green", false), ("Blue", false)]);
|
||||
}
|
||||
|
||||
const ORPHAN_FIELDS: &[u8] = b"%PDF-1.7
|
||||
1 0 obj << /Type /Catalog /Pages 2 0 R /AcroForm 4 0 R >> endobj
|
||||
2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj
|
||||
|
||||
@@ -1362,6 +1362,8 @@
|
||||
This document has no layers. هذا المستند لا يحتوي على طبقات.
|
||||
This document has no attachments. هذا المستند لا يحتوي على مرفقات.
|
||||
Hide layer إخفاء الطبقة
|
||||
Layer options خيارات الطبقات
|
||||
Reset to Initial Visibility إعادة تعيين إلى الرؤية الأولية
|
||||
Show layer إظهار الطبقة
|
||||
Set layer visibility ضبط ظهور الطبقة
|
||||
on page {label} في الصفحة {label}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -1304,6 +1304,8 @@
|
||||
This document has no layers. Този документ няма слоеве.
|
||||
This document has no attachments. Този документ няма прикачени файлове.
|
||||
Hide layer Скрий слоя
|
||||
Layer options Опции за слоеве
|
||||
Reset to Initial Visibility Възстанови първоначалната видимост
|
||||
Show layer Покажи слоя
|
||||
Set layer visibility Задай видимост на слоя
|
||||
on page {label} на страница {label}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 8 and column 16.
|
@@ -1431,6 +1431,8 @@ key Space Mezerník
|
||||
This document has no layers. Tento dokument nemá žádné vrstvy.
|
||||
This document has no attachments. Tento dokument nemá žádné přílohy.
|
||||
Hide layer Skrýt vrstvu
|
||||
Layer options Možnosti vrstev
|
||||
Reset to Initial Visibility Obnovit počáteční viditelnost
|
||||
Show layer Zobrazit vrstvu
|
||||
Set layer visibility Nastavit viditelnost vrstvy
|
||||
on page {label} na stránce {label}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -1348,6 +1348,8 @@
|
||||
This document has no layers. Dieses Dokument hat keine Ebenen.
|
||||
This document has no attachments. Dieses Dokument hat keine Anhänge.
|
||||
Hide layer Ebene ausblenden
|
||||
Layer options Ebenenoptionen
|
||||
Reset to Initial Visibility Ursprüngliche Sichtbarkeit wiederherstellen
|
||||
Show layer Ebene einblenden
|
||||
on page {label} auf Seite {label}
|
||||
Save attachment… Anhang speichern…
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 51.
|
@@ -363,6 +363,8 @@
|
||||
Distribute Κατανομή
|
||||
Show layer Εμφάνιση επιπέδου
|
||||
Hide layer Απόκρυψη επιπέδου
|
||||
Layer options Επιλογές επιπέδων
|
||||
Reset to Initial Visibility Επαναφορά αρχικής ορατότητας
|
||||
Collate Συρραφή αντιγράφων
|
||||
Fit to page Προσαρμογή στη σελίδα
|
||||
Reverse pages Αντιστροφή σειράς σελίδων
|
||||
|
||||
|
@@ -1357,6 +1357,8 @@
|
||||
This document has no layers. Este documento no tiene capas.
|
||||
This document has no attachments. Este documento no tiene archivos adjuntos.
|
||||
Hide layer Ocultar capa
|
||||
Layer options Opciones de capas
|
||||
Reset to Initial Visibility Restablecer visibilidad inicial
|
||||
Show layer Mostrar capa
|
||||
Set layer visibility Definir visibilidad de capas
|
||||
on page {label} en la página {label}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 60.
|
@@ -1343,6 +1343,8 @@
|
||||
This document has no layers. Ce document ne contient aucun calque.
|
||||
This document has no attachments. Ce document ne contient aucune pièce jointe.
|
||||
Hide layer Masquer le calque
|
||||
Layer options Options des calques
|
||||
Reset to Initial Visibility Rétablir la visibilité initiale
|
||||
Show layer Afficher le calque
|
||||
on page {label} à la page {label}
|
||||
Save attachment… Enregistrer la pièce jointe…
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 39.
|
@@ -1333,6 +1333,8 @@
|
||||
This document has no layers. Ebben a dokumentumban nincs réteg.
|
||||
This document has no attachments. Ebben a dokumentumban nincs melléklet.
|
||||
Hide layer Réteg elrejtése
|
||||
Layer options Réteg beállításai
|
||||
Reset to Initial Visibility Kezdeti láthatóság visszaállítása
|
||||
Show layer Réteg megjelenítése
|
||||
on page {label} {label}. oldal
|
||||
Save attachment… Melléklet mentése…
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 7 and column 44.
|
@@ -1358,6 +1358,8 @@
|
||||
This document has no layers. Questo documento non ha livelli.
|
||||
This document has no attachments. Questo documento non ha allegati.
|
||||
Hide layer Nascondi livello
|
||||
Layer options Opzioni livelli
|
||||
Reset to Initial Visibility Ripristina visibilità iniziale
|
||||
Show layer Mostra livello
|
||||
Set layer visibility Imposta visibilità livello
|
||||
on page {label} a pagina {label}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -1363,6 +1363,8 @@
|
||||
This document has no layers. この文書にレイヤーはありません。
|
||||
This document has no attachments. この文書に添付ファイルはありません。
|
||||
Hide layer レイヤーを非表示
|
||||
Layer options レイヤーのオプション
|
||||
Reset to Initial Visibility 初期表示状態にリセット
|
||||
Show layer レイヤーを表示
|
||||
Set layer visibility レイヤーの表示を設定
|
||||
on page {label} ページ {label}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -1305,6 +1305,8 @@
|
||||
This document has no layers. Бұл құжатта қабаттар жоқ.
|
||||
This document has no attachments. Бұл құжатта тіркемелер жоқ.
|
||||
Hide layer Қабатты жасыру
|
||||
Layer options Қабат параметрлері
|
||||
Reset to Initial Visibility Бастапқы көрінуді қалпына келтіру
|
||||
Show layer Қабатты көрсету
|
||||
Set layer visibility Қабаттың көрінісін орнату
|
||||
on page {label} {label} бетінде
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 856 and column 9.
|
@@ -629,6 +629,8 @@
|
||||
Height: Aukštis:
|
||||
Hide field highlights Slėpti laukų paryškinimą
|
||||
Hide layer Slėpti sluoksnį
|
||||
Layer options Sluoksnių parinktys
|
||||
Reset to Initial Visibility Atkurti pradinį matomumą
|
||||
Hide menu bar Slėpti meniu juostą
|
||||
Hide password Slėpti slaptažodį
|
||||
Hide toolbars Slėpti įrankių juostas
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 404 and column 9.
|
@@ -1348,6 +1348,8 @@
|
||||
This document has no layers. Ten dokument nie zawiera warstw.
|
||||
This document has no attachments. Ten dokument nie zawiera załączników.
|
||||
Hide layer Ukryj warstwę
|
||||
Layer options Opcje warstw
|
||||
Reset to Initial Visibility Przywróć początkową widoczność
|
||||
Show layer Pokaż warstwę
|
||||
Set layer visibility Ustaw widoczność warstwy
|
||||
on page {label} na stronie {label}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -1248,6 +1248,8 @@
|
||||
This document has no layers. Este documento não tem camadas.
|
||||
This document has no attachments. Este documento não tem anexos.
|
||||
Hide layer Ocultar camada
|
||||
Layer options Opções de camadas
|
||||
Reset to Initial Visibility Redefinir visibilidade inicial
|
||||
Show layer Mostrar camada
|
||||
on page {label} na página {label}
|
||||
Save attachment… Salvar anexo…
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -1363,6 +1363,8 @@
|
||||
This document has no layers. В этом документе нет слоёв.
|
||||
This document has no attachments. В этом документе нет вложений.
|
||||
Hide layer Скрыть слой
|
||||
Layer options Параметры слоёв
|
||||
Reset to Initial Visibility Восстановить исходную видимость
|
||||
Show layer Показать слой
|
||||
Set layer visibility Задать видимость слоя
|
||||
on page {label} на стр. {label}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -902,6 +902,8 @@
|
||||
Hide all comments Skrij vse komentarje
|
||||
Hide field highlights Skrij osvetlitev polj
|
||||
Hide layer Skrij plast
|
||||
Layer options Možnosti plasti
|
||||
Reset to Initial Visibility Ponastavi na začetno vidnost
|
||||
Hide menu bar Skrij menijsko vrstico
|
||||
Hide password Skrij geslo
|
||||
Hide toolbars Skrij orodne vrstice
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -1333,6 +1333,8 @@ signature pad Type టైప్ చేయి
|
||||
This document has no layers. ఈ పత్రంలో లేయర్లు లేవు.
|
||||
This document has no attachments. ఈ పత్రంలో జోడింపులు లేవు.
|
||||
Hide layer లేయర్ను దాచు
|
||||
Layer options లేయర్ ఎంపికలు
|
||||
Reset to Initial Visibility ప్రారంభ దృశ్యతకు రీసెట్ చేయి
|
||||
Show layer లేయర్ను చూపించు
|
||||
on page {label} పేజీ {label}లో
|
||||
Save attachment… జోడింపును సేవ్ చేయి…
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 13 and column 16.
|
@@ -1320,6 +1320,8 @@
|
||||
This document has no layers. Bu belgede katman yok.
|
||||
This document has no attachments. Bu belgede ek yok.
|
||||
Hide layer Katmanı gizle
|
||||
Layer options Katman seçenekleri
|
||||
Reset to Initial Visibility Başlangıç görünürlüğüne sıfırla
|
||||
Show layer Katmanı göster
|
||||
on page {label} sayfa {label} üzerinde
|
||||
Save attachment… Eki kaydet…
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 855 and column 9.
|
@@ -1360,6 +1360,8 @@
|
||||
This document has no layers. Цей документ не має шарів.
|
||||
This document has no attachments. Цей документ не має вкладень.
|
||||
Hide layer Приховати шар
|
||||
Layer options Параметри шарів
|
||||
Reset to Initial Visibility Відновити початкову видимість
|
||||
Show layer Показати шар
|
||||
Set layer visibility Задати видимість шару
|
||||
on page {label} на сторінці {label}
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 6 and column 47.
|
@@ -625,6 +625,8 @@ theme Appearance Giao diện
|
||||
Height: Chiều cao:
|
||||
Hide field highlights Ẩn tô sáng trường
|
||||
Hide layer Ẩn lớp
|
||||
Layer options Tùy chọn lớp
|
||||
Reset to Initial Visibility Đặt lại khả năng hiển thị ban đầu
|
||||
Hide menu bar Ẩn thanh trình đơn
|
||||
Hide password Ẩn mật khẩu
|
||||
Hide toolbars Ẩn thanh công cụ
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 491 and column 12.
|
@@ -1311,6 +1311,8 @@
|
||||
This document has no layers. 本文档没有图层。
|
||||
This document has no attachments. 本文档没有附件。
|
||||
Hide layer 隐藏图层
|
||||
Layer options 图层选项
|
||||
Reset to Initial Visibility 重置为初始可见性
|
||||
Show layer 显示图层
|
||||
Set layer visibility 设置图层可见性
|
||||
on page {label} 第 {label} 页
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -1255,6 +1255,8 @@
|
||||
This document has no layers. 本文件沒有圖層。
|
||||
This document has no attachments. 本文件沒有附件。
|
||||
Hide layer 隱藏圖層
|
||||
Layer options 圖層選項
|
||||
Reset to Initial Visibility 重設為初始可見性
|
||||
Show layer 顯示圖層
|
||||
Set layer visibility 設定圖層可見性
|
||||
on page {label} 第 {label} 頁
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 9 and column 16.
|
@@ -653,6 +653,7 @@ pub fn right_panel(app: &mut PdfCraftApp, ui: &mut egui::Ui) {
|
||||
let mut nav: Option<Nav> = None;
|
||||
let mut close = false;
|
||||
let mut toggle_layer: Option<(usize, bool)> = None;
|
||||
let mut reset_layers = false;
|
||||
let mut attachment_action: Option<(usize, bool)> = None; // (index, open instead of save)
|
||||
let mut bm_action: Option<BmAction> = None;
|
||||
let mut bm_expand: Option<usize> = None;
|
||||
@@ -745,6 +746,16 @@ pub fn right_panel(app: &mut PdfCraftApp, ui: &mut egui::Ui) {
|
||||
}
|
||||
});
|
||||
}
|
||||
if panel == RightPanel::Layers && !info.layers.is_empty() {
|
||||
let more = icons::button(ui, "ellipsis", 26.0, false, tl!("Layer options"));
|
||||
egui::Popup::menu(&more).show(|ui| {
|
||||
ui.set_min_width(200.0);
|
||||
if ui.button(tl!("Reset to Initial Visibility")).clicked() {
|
||||
reset_layers = true;
|
||||
ui.close();
|
||||
}
|
||||
});
|
||||
}
|
||||
let new_tip = crate::commands::command_tip(ui.ctx(), tl!("New bookmark ({key})"), "bookmark.add");
|
||||
if panel == RightPanel::Bookmarks && bm_editable && icons::button(ui, "bookmark-plus", 26.0, false, &new_tip).clicked() {
|
||||
bm_action = Some(BmAction::New);
|
||||
@@ -968,6 +979,9 @@ pub fn right_panel(app: &mut PdfCraftApp, ui: &mut egui::Ui) {
|
||||
{
|
||||
app.views[index].invalidate_content();
|
||||
}
|
||||
if reset_layers && app.session.reset_layers(id) {
|
||||
app.views[index].invalidate_content();
|
||||
}
|
||||
match nav {
|
||||
Some(Nav::Page(p)) => app.views[index].go_to_page(p),
|
||||
Some(Nav::Dest(p, dest)) => match app.session.get(id) {
|
||||
|
||||
@@ -104,3 +104,23 @@ fn push_buttons_set_layer_visibility() {
|
||||
let s = h.state();
|
||||
assert!(!s.session.get(s.views[0].id).unwrap().dirty, "showing and hiding layers doesn't change the document");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn layer_options_reset_to_initial_visibility() {
|
||||
// Red off and Green on: the opposite of how the file opens.
|
||||
let mut h = harness(|app| {
|
||||
app.set_option("layer", "Red=off").unwrap();
|
||||
app.set_option("layer", "Green=on").unwrap();
|
||||
app.set_option("panel", "layers").unwrap();
|
||||
});
|
||||
assert_eq!(shown(&h), layers(false, true));
|
||||
h.get_by_label("Layer options").click();
|
||||
h.run_steps(2);
|
||||
h.get_by_label("Reset to Initial Visibility").click();
|
||||
h.run_steps(3);
|
||||
assert_eq!(shown(&h), layers(true, false));
|
||||
let s = h.state();
|
||||
let doc = s.session.get(s.views[0].id).unwrap();
|
||||
assert!(!doc.dirty, "showing and hiding layers doesn't change the document");
|
||||
assert_eq!(doc.can_undo(), None, "nor is it an edit to undo");
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ are borrowed; PDF 2.0 additions and most subset standards are missing. **150–2
|
||||
| §14.12 | Document parts (DPart) | yes | none | `core.pdf20-dpart` planned |
|
||||
| §14.13 | Associated files (`/AF`) | yes | none | `core.pdf20-associated-files` planned |
|
||||
| — | Structural validation (Arlington PDF model) | yes (Preflight syntax checks) | none | `core.arlington-validation` planned |
|
||||
| — | Optional content (layers) | full | **own** toggle and default state; set-OCG-state actions; no layer editing | `view.layers-panel` |
|
||||
| — | Optional content (layers) | full | **own** toggle and default state, reset to the default state; set-OCG-state actions; no layer editing | `view.layers-panel`, `view.layers-reset` |
|
||||
| — | Redaction (`/Redact` annotations, applying) | full | **own**: removes glyphs, image pixels, vectors, XObject content, annotations, fields and tags; verifies no residue | `protect.redact-*`, `protect.redaction-verification` |
|
||||
|
||||
## Annotations (§12.5.6)
|
||||
|
||||
@@ -1331,11 +1331,11 @@ title = "Reset layers to initial visibility; list for all or current pages"
|
||||
area = "B"
|
||||
tier = "P2"
|
||||
milestone = "M12"
|
||||
status = "planned"
|
||||
status = "partial"
|
||||
commands = []
|
||||
tools = []
|
||||
evidence = []
|
||||
notes = ""
|
||||
tools = ["doc_info"]
|
||||
evidence = ["crates/engine/src/tests.rs::reset_layers_returns_to_the_files_visibility", "crates/render/src/inspect.rs::initial_layer_visibility_is_the_default_configuration"]
|
||||
notes = "Layers panel ▸ Layer options ▸ Reset to Initial Visibility shows each layer as the default configuration (/OCProperties /D) has it; doc_info reports it as `initial`. Not yet: listing the layers of all pages or the current page only."
|
||||
|
||||
[[feature]]
|
||||
id = "view.destinations-panel"
|
||||
|
||||
Reference in New Issue
Block a user