feat: Neue Seite direkt nach der aktuellen einfügen
„Neue Seite einfügen“ (☰-Menü und Seitenauswahl) legt die leere Seite direkt hinter der aktuellen an und wechselt dorthin, statt sie ans Ende zu hängen – etwa zwischen zwei Folien eines PDFs (Issue #3). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -55,7 +55,7 @@ Eine latenzoptimierte, hardwarebeschleunigte Inking- und Notizbuch-Anwendung fü
|
|||||||
### 📄 Seiten & Hintergründe
|
### 📄 Seiten & Hintergründe
|
||||||
- **Virtuelles DIN-A4-Raster:** 2100 × 2970 Koordinateneinheiten (10 Einheiten = 1 mm).
|
- **Virtuelles DIN-A4-Raster:** 2100 × 2970 Koordinateneinheiten (10 Einheiten = 1 mm).
|
||||||
- **Hintergrundmuster:** Blanko, Kariert (5 mm), Liniert (7.5 mm), Punktraster (5 mm).
|
- **Hintergrundmuster:** Blanko, Kariert (5 mm), Liniert (7.5 mm), Punktraster (5 mm).
|
||||||
- **Seitenverwaltung:** Vor- und Zurückblättern, neue Seiten anfügen, Seitensprung-Menü.
|
- **Seitenverwaltung:** Vor- und Zurückblättern, neue Seiten anhängen oder direkt nach der aktuellen Seite einfügen (☰-Menü oder Seitenauswahl, z. B. zwischen zwei PDF-Folien), Seitensprung-Menü.
|
||||||
|
|
||||||
### 💾 Autosave & Persistenz
|
### 💾 Autosave & Persistenz
|
||||||
- **Asynchroner Autosave-Controller:** Sichert Änderungen im Hintergrund nach 1.5 s Ruhezeit (Debounce), ohne das Zeichnen zu blockieren.
|
- **Asynchroner Autosave-Controller:** Sichert Änderungen im Hintergrund nach 1.5 s Ruhezeit (Debounce), ohne das Zeichnen zu blockieren.
|
||||||
|
|||||||
@@ -1149,6 +1149,16 @@ impl Notebook {
|
|||||||
self.pages.len() - 1
|
self.pages.len() - 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Fügt direkt nach der aktuellen Seite eine leere Seite mit dem angegebenen
|
||||||
|
/// Hintergrund ein (die aktuelle Seite bleibt aktuell) und gibt ihren Index zurück.
|
||||||
|
pub fn insert_page_after_current(&mut self, background: PageBackground) -> usize {
|
||||||
|
let id = self.next_page_id;
|
||||||
|
self.next_page_id += 1;
|
||||||
|
let index = (self.current_page_index + 1).min(self.pages.len());
|
||||||
|
self.pages.insert(index, Page::new(id, background));
|
||||||
|
index
|
||||||
|
}
|
||||||
|
|
||||||
/// Durchgehende Ansicht: Reicht ein neuer Strich auf der letzten Seite bis in deren
|
/// Durchgehende Ansicht: Reicht ein neuer Strich auf der letzten Seite bis in deren
|
||||||
/// unteres Fünftel ([`AUTO_APPEND_ZONE`]), wird darunter eine leere Seite mit gleichem
|
/// unteres Fünftel ([`AUTO_APPEND_ZONE`]), wird darunter eine leere Seite mit gleichem
|
||||||
/// Hintergrund angehängt. `true`, wenn eine Seite angehängt wurde.
|
/// Hintergrund angehängt. `true`, wenn eine Seite angehängt wurde.
|
||||||
@@ -1809,6 +1819,27 @@ mod tests {
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_insert_page_after_current() {
|
||||||
|
let mut nb = Notebook::new();
|
||||||
|
nb.add_page(PageBackground::Lined);
|
||||||
|
nb.add_page(PageBackground::Lined);
|
||||||
|
let ids: Vec<u64> = nb.pages.iter().map(|p| p.id).collect();
|
||||||
|
nb.current_page_index = 1;
|
||||||
|
nb.pages[1].background = PageBackground::DotGrid;
|
||||||
|
let index = nb.insert_page_after_current(PageBackground::DotGrid);
|
||||||
|
assert_eq!(index, 2);
|
||||||
|
assert_eq!(nb.current_page_index, 1);
|
||||||
|
assert_eq!(nb.pages.len(), 4);
|
||||||
|
assert_eq!(nb.pages[0].id, ids[0]);
|
||||||
|
assert_eq!(nb.pages[1].id, ids[1]);
|
||||||
|
assert_eq!(nb.pages[3].id, ids[2], "alte Seite 3 ist jetzt Seite 4");
|
||||||
|
let new = &nb.pages[2];
|
||||||
|
assert!(!ids.contains(&new.id) && new.strokes.is_empty());
|
||||||
|
assert_eq!(new.background, PageBackground::DotGrid);
|
||||||
|
assert!(new.pdf_background.is_none());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_append_page_when_writing_at_bottom_of_last_page() {
|
fn test_append_page_when_writing_at_bottom_of_last_page() {
|
||||||
let mut nb = Notebook::new();
|
let mut nb = Notebook::new();
|
||||||
|
|||||||
+16
-18
@@ -2800,26 +2800,24 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
UiAction::AddPage => {
|
UiAction::AddPage => {
|
||||||
selection_state.clear();
|
// Leere Seite direkt nach der aktuellen (in PDFs: nach der Folie,
|
||||||
|
// auf der man gerade ist) und dorthin wechseln
|
||||||
let bg = notebook.current_page().background;
|
let bg = notebook.current_page().background;
|
||||||
notebook.add_page(bg);
|
let index = notebook.insert_page_after_current(bg);
|
||||||
manifest.current_page_index = notebook.current_page_index;
|
|
||||||
manifest.next_page_id = notebook.next_page_id;
|
|
||||||
manifest.pages = notebook
|
|
||||||
.pages
|
|
||||||
.iter()
|
|
||||||
.map(|p| storage::PageMeta {
|
|
||||||
id: p.id,
|
|
||||||
background: Some(p.background),
|
|
||||||
title: p.title.clone(),
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
canvas.sync_page(notebook.current_page_mut());
|
|
||||||
manifest.sync_from_notebook(¬ebook);
|
manifest.sync_from_notebook(¬ebook);
|
||||||
autosave.mark_manifest_dirty(&manifest);
|
switch_to_page(
|
||||||
autosave.mark_dirty(¬ebook, &mut manifest);
|
index,
|
||||||
update_window_title(&window, ¬ebook, &manifest, ui_state.active_tool, autosave.status());
|
false,
|
||||||
window.request_redraw();
|
&mut canvas,
|
||||||
|
&mut notebook,
|
||||||
|
&mut manifest,
|
||||||
|
&mut autosave,
|
||||||
|
&storage_dir,
|
||||||
|
&mut selection_state,
|
||||||
|
&mut ui_state,
|
||||||
|
&window,
|
||||||
|
);
|
||||||
|
ui_state.set_export_message(format!("Seite {} eingefügt", index + 1));
|
||||||
}
|
}
|
||||||
UiAction::LoadAllPages => {
|
UiAction::LoadAllPages => {
|
||||||
// Für die Vorschaubilder der Seitenauswahl; Fehler werden wie beim
|
// Für die Vorschaubilder der Seitenauswahl; Fehler werden wie beim
|
||||||
|
|||||||
@@ -2561,7 +2561,8 @@ pub fn render_ui(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
if ui
|
if ui
|
||||||
.add_sized([ui.available_width(), 30.0], egui::Button::new("➕ Neue Seite anhängen"))
|
.add_sized([ui.available_width(), 30.0], egui::Button::new("➕ Neue Seite einfügen"))
|
||||||
|
.on_hover_text("Leere Seite direkt nach der aktuellen Seite")
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
actions.push(UiAction::AddPage);
|
actions.push(UiAction::AddPage);
|
||||||
@@ -2883,8 +2884,9 @@ pub fn render_ui(
|
|||||||
if ui
|
if ui
|
||||||
.add_sized(
|
.add_sized(
|
||||||
[ui.available_width(), 36.0],
|
[ui.available_width(), 36.0],
|
||||||
egui::Button::new("➕ Neue Seite anhängen"),
|
egui::Button::new("➕ Neue Seite einfügen"),
|
||||||
)
|
)
|
||||||
|
.on_hover_text("Leere Seite direkt nach der aktuellen Seite")
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
actions.push(UiAction::AddPage);
|
actions.push(UiAction::AddPage);
|
||||||
|
|||||||
Reference in New Issue
Block a user