feat: Seitenanordnung je Notizbuch (Issue #30, Schritt 1)

Ob ein Notizbuch Seite für Seite oder durchgehend angezeigt wird, steht
jetzt im Manifest (`layout`). Beim Anlegen ist „Feste Seiten“
vorgewählt; im ☰-Menü lässt sich die Anordnung des offenen Notizbuchs
umschalten. Notizbücher ohne Angabe behalten die frühere globale
Einstellung, ältere App-Versionen ignorieren das Feld.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-18 21:58:55 +02:00
co-authored by Claude Opus 5.5
parent 1b30f2bd26
commit 8ea20aa783
8 changed files with 128 additions and 26 deletions
+1 -1
View File
@@ -49,7 +49,7 @@ Die Oberfläche gibt es auf Deutsch und Englisch; ink-notes folgt der Systemspra
### Seiten und Ansicht ### Seiten und Ansicht
- **Hintergründe:** blanko, kariert (5 mm), liniert (7,5 mm), Punktraster (5 mm). Die **Farbe von Karos, Linien und Punkten** ist wählbar (hell, mittel, kräftig, blau, grün) und gilt auch im Export. - **Hintergründe:** blanko, kariert (5 mm), liniert (7,5 mm), Punktraster (5 mm). Die **Farbe von Karos, Linien und Punkten** ist wählbar (hell, mittel, kräftig, blau, grün) und gilt auch im Export.
- **Papierfarbe** der Anzeige: weiß, creme, dunkelgrau, schwarz; auf dunklem Papier werden dunkle Stiftfarben auf Wunsch aufgehellt. Gespeichert und exportiert wird immer auf weißem Papier. - **Papierfarbe** der Anzeige: weiß, creme, dunkelgrau, schwarz; auf dunklem Papier werden dunkle Stiftfarben auf Wunsch aufgehellt. Gespeichert und exportiert wird immer auf weißem Papier.
- **Durchgehendes Scrollen:** Seiten hängen lückenlos untereinander, eine dunkle Linie markiert die Grenze; wer im unteren Fünftel der letzten Seite schreibt, bekommt automatisch eine neue Seite. Abschaltbar (dann Seite für Seite blättern, mit Pfeilen in der Werkzeugleiste). - **Feste Seiten oder durchgehendes Scrollen, je Notizbuch:** Beim Anlegen wählbar (Vorgabe: feste Seiten, Seite für Seite blättern mit Pfeilen in der Werkzeugleiste), später im ☰-Menü umschaltbar. Durchgehend hängen die Seiten lückenlos untereinander, eine dunkle Linie markiert die Grenze; wer im unteren Fünftel der letzten Seite schreibt, bekommt automatisch eine neue Seite.
- **Seiten einfügen und löschen:** ➕ in der Werkzeugleiste fügt nach der aktuellen Seite eine leere Seite ein. Löschen im ☰-Menü (mit Rückfrage); die zuletzt gelöschte Seite lässt sich dort wiederherstellen, solange die App läuft. - **Seiten einfügen und löschen:** ➕ in der Werkzeugleiste fügt nach der aktuellen Seite eine leere Seite ein. Löschen im ☰-Menü (mit Rückfrage); die zuletzt gelöschte Seite lässt sich dort wiederherstellen, solange die App läuft.
- **Zoom** von 25 % bis 1000 % (`Strg + Mausrad`, zwei Finger, `Strg + +/-/0`), Verschieben mit mittlerer Maustaste, `Leertaste + Ziehen` oder einem Finger. - **Zoom** von 25 % bis 1000 % (`Strg + Mausrad`, zwei Finger, `Strg + +/-/0`), Verschieben mit mittlerer Maustaste, `Leertaste + Ziehen` oder einem Finger.
- **Seiten** anhängen oder direkt nach der aktuellen Seite einfügen, **Seitentitel** vergeben; die Seitenübersicht zeigt Vorschaubilder oder ein Inhaltsverzeichnis. Seitentitel werden im PDF zu Lesezeichen. - **Seiten** anhängen oder direkt nach der aktuellen Seite einfügen, **Seitentitel** vergeben; die Seitenübersicht zeigt Vorschaubilder oder ein Inhaltsverzeichnis. Seitentitel werden im PDF zu Lesezeichen.
+2
View File
@@ -93,6 +93,8 @@ $$\vec{p}_{\text{neu}} = \vec{c} - (\vec{c} - \vec{p}_{\text{alt}}) \cdot \frac{
- Im Shader wird jeder Punkt mit `transform_scale` und `transform_offset` (aus `CameraUniforms`) direkt in Gerätekoordinaten umgerechnet. - Im Shader wird jeder Punkt mit `transform_scale` und `transform_offset` (aus `CameraUniforms`) direkt in Gerätekoordinaten umgerechnet.
### 3.3 Durchgehende Ansicht ### 3.3 Durchgehende Ansicht
Ob ein Notizbuch Seite für Seite oder durchgehend angezeigt wird, steht in seinem Manifest (`layout`, siehe [`FILE_FORMAT.md`](FILE_FORMAT.md)).
Alle Koordinaten beziehen sich auf die **aktuelle Seite**. `PageStack` (`viewport.rs`) legt die übrigen Seiten lückenlos darunter bzw. darüber (die Grenze zeichnet die Oberfläche als dunkle Linie), waagerecht zur aktuellen Seite zentriert. Jede sichtbare Nachbarseite wird mit einer eigenen Kamera gezeichnet, die um die Lage der Seite verschoben ist (höchstens 12 Nachbarseiten). Alle Koordinaten beziehen sich auf die **aktuelle Seite**. `PageStack` (`viewport.rs`) legt die übrigen Seiten lückenlos darunter bzw. darüber (die Grenze zeichnet die Oberfläche als dunkle Linie), waagerecht zur aktuellen Seite zentriert. Jede sichtbare Nachbarseite wird mit einer eigenen Kamera gezeichnet, die um die Lage der Seite verschoben ist (höchstens 12 Nachbarseiten).
Nach dem Scrollen wird die Seite in der Fenstermitte zur aktuellen Seite; die Kamera wird dabei so verschoben, dass sich das Bild nicht bewegt. Während eines Strichs, einer Auswahl, beim Ziehen des Lineals oder beim Schreiben von Text wird nicht gewechselt. Wer auf einer sichtbaren Nachbarseite zu zeichnen beginnt, wechselt zuerst auf diese Seite. Nach dem Scrollen wird die Seite in der Fenstermitte zur aktuellen Seite; die Kamera wird dabei so verschoben, dass sich das Bild nicht bewegt. Während eines Strichs, einer Auswahl, beim Ziehen des Lineals oder beim Schreiben von Text wird nicht gewechselt. Wer auf einer sichtbaren Nachbarseite zu zeichnen beginnt, wechselt zuerst auf diese Seite.
+3 -1
View File
@@ -63,7 +63,8 @@ Ordner wie „3. Semester › Mathe“ sind rein logisch: Die Notizbücher bleib
], ],
"page_ids": [1, 2], "page_ids": [1, 2],
"next_stroke_id": 42, "next_stroke_id": 42,
"next_page_id": 3 "next_page_id": 3,
"layout": "Paged"
} }
``` ```
@@ -76,6 +77,7 @@ Ordner wie „3. Semester › Mathe“ sind rein logisch: Die Notizbücher bleib
| `pages` | Seiten in ihrer Reihenfolge: `id`, `background`, optional `title` und `size` (siehe unten) – damit Seitenübersicht und Ansicht sie kennen, ohne jede Seite zu laden | | `pages` | Seiten in ihrer Reihenfolge: `id`, `background`, optional `title` und `size` (siehe unten) – damit Seitenübersicht und Ansicht sie kennen, ohne jede Seite zu laden |
| `page_ids` | dieselbe Reihenfolge als reine ID-Liste (für ältere Versionen) | | `page_ids` | dieselbe Reihenfolge als reine ID-Liste (für ältere Versionen) |
| `next_stroke_id`, `next_page_id` | nächste freie IDs | | `next_stroke_id`, `next_page_id` | nächste freie IDs |
| `layout` | Anordnung der Seiten: `Paged` (Seite für Seite) oder `Continuous` (durchgehend untereinander). Seit 0.28; fehlt das Feld, gilt die frühere globale Einstellung `continuous_scroll` aus `ui.json`. Ältere App-Versionen ignorieren es, daher keine neue Formatversion |
--- ---
+6 -3
View File
@@ -20,8 +20,6 @@ pub const EN: &[(&str, &str)] = &[
("Alle", "All"), ("Alle", "All"),
("Alles gespeichert", "All saved"), ("Alles gespeichert", "All saved"),
("Als leere Seite bearbeiten (Schreibschutz aufheben)", "Edit as blank page (remove write protection)"), ("Als leere Seite bearbeiten (Schreibschutz aufheben)", "Edit as blank page (remove write protection)"),
("An: Seiten hängen untereinander, Mausrad und Finger scrollen (Strg+Mausrad zoomt); wer unten auf der letzten Seite schreibt, bekommt automatisch eine neue Seite.\nAus: Seite für Seite blättern.", "On: pages are stacked, mouse wheel and finger scroll (Ctrl+wheel zooms); writing at the bottom of the last page adds a new page automatically.\nOff: flip page by page."),
("ANSICHT", "VIEW"),
("AppImage (Portabel)", "AppImage (portable)"), ("AppImage (Portabel)", "AppImage (portable)"),
("Asset-Name darf nicht leer sein.", "Asset name must not be empty."), ("Asset-Name darf nicht leer sein.", "Asset name must not be empty."),
("Auch per Strg+V aus der Zwischenablage oder durch Ziehen einer Bilddatei ins Fenster", "Also with Ctrl+V from the clipboard or by dragging an image file into the window"), ("Auch per Strg+V aus der Zwischenablage oder durch Ziehen einer Bilddatei ins Fenster", "Also with Ctrl+V from the clipboard or by dragging an image file into the window"),
@@ -267,6 +265,7 @@ pub const EN: &[(&str, &str)] = &[
("Schwarz", "Black"), ("Schwarz", "Black"),
("Sechseck (Hexagon)", "Hexagon"), ("Sechseck (Hexagon)", "Hexagon"),
("Seite als", "Page as"), ("Seite als", "Page as"),
("Seite für Seite blättern", "Flip page by page"),
("Seite ist schreibgeschützt", "Page is read-only"), ("Seite ist schreibgeschützt", "Page is read-only"),
("Seite konnte nicht geladen werden", "Page could not be loaded"), ("Seite konnte nicht geladen werden", "Page could not be loaded"),
("Seite wird exportiert …", "Exporting page …"), ("Seite wird exportiert …", "Exporting page …"),
@@ -285,7 +284,9 @@ pub const EN: &[(&str, &str)] = &[
("Seite {number} – {title}", "Page {number} – {title}"), ("Seite {number} – {title}", "Page {number} – {title}"),
("Seite {number}", "Page {number}"), ("Seite {number}", "Page {number}"),
("Seiten ({count})", "Pages ({count})"), ("Seiten ({count})", "Pages ({count})"),
("Seiten durchgehend scrollen", "Scroll pages continuously"), ("SEITEN DIESES NOTIZBUCHS", "PAGES OF THIS NOTEBOOK"),
("Seiten hängen untereinander, Mausrad und Finger scrollen (Strg+Mausrad zoomt); wer unten auf der letzten Seite schreibt, bekommt automatisch eine neue Seite.", "Pages are stacked, mouse wheel and finger scroll (Ctrl+wheel zooms); writing at the bottom of the last page adds a new page automatically."),
("Seiten:", "Pages:"),
("Seitenverhältnis frei – tippen zum Sperren", "Aspect ratio free – tap to lock"), ("Seitenverhältnis frei – tippen zum Sperren", "Aspect ratio free – tap to lock"),
("Seitenverhältnis gesperrt – tippen zum Freigeben", "Aspect ratio locked – tap to unlock"), ("Seitenverhältnis gesperrt – tippen zum Freigeben", "Aspect ratio locked – tap to unlock"),
("Serialisierungsfehler: {e}", "Serialization error: {e}"), ("Serialisierungsfehler: {e}", "Serialization error: {e}"),
@@ -418,12 +419,14 @@ pub const EN: &[(&str, &str)] = &[
("📂 Ordner öffnen", "📂 Open folder"), ("📂 Ordner öffnen", "📂 Open folder"),
("📄 Als PDF exportieren (Strg+E)", "📄 Export as PDF (Ctrl+E)"), ("📄 Als PDF exportieren (Strg+E)", "📄 Export as PDF (Ctrl+E)"),
("📄 PDF importieren …", "📄 Import PDF …"), ("📄 PDF importieren …", "📄 Import PDF …"),
("📄 Feste Seiten", "📄 Fixed pages"),
("📄 PDF importieren", "📄 Import PDF"), ("📄 PDF importieren", "📄 Import PDF"),
("📋 Einfügen", "📋 Paste"), ("📋 Einfügen", "📋 Paste"),
("📑 Inhalt", "📑 Contents"), ("📑 Inhalt", "📑 Contents"),
("📚 Alle", "📚 All"), ("📚 Alle", "📚 All"),
("📚 Notizbücher", "📚 Notebooks"), ("📚 Notizbücher", "📚 Notebooks"),
("📚 Oberste Ebene", "📚 Top level"), ("📚 Oberste Ebene", "📚 Top level"),
("📜 Durchgehend", "📜 Continuous"),
("📦 Paket mit Software-Center öffnen / installieren", "📦 Open / install package with the software center"), ("📦 Paket mit Software-Center öffnen / installieren", "📦 Open / install package with the software center"),
("🔄 Suche nach Updates …", "🔄 Checking for updates …"), ("🔄 Suche nach Updates …", "🔄 Checking for updates …"),
("🔄 Updates & Versionen", "🔄 Updates & versions"), ("🔄 Updates & Versionen", "🔄 Updates & versions"),
+12 -6
View File
@@ -36,7 +36,7 @@ use ink_notes::selection::{
use ink_notes::settings::{ use ink_notes::settings::{
SidebarSide, StylusAction, StylusButton, UiSettings, MAX_STYLUS_BUTTONS, SidebarSide, StylusAction, StylusButton, UiSettings, MAX_STYLUS_BUTTONS,
}; };
use ink_notes::storage::{self, NotebookManifest}; use ink_notes::storage::{self, NotebookLayout, NotebookManifest};
use ink_notes::t; use ink_notes::t;
use ink_notes::ui::{self, ActiveTool, UiAction, UiState}; use ink_notes::ui::{self, ActiveTool, UiAction, UiState};
use ink_notes::updater::UpdaterController; use ink_notes::updater::UpdaterController;
@@ -1522,6 +1522,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
event_loop.run(move |event, target| { event_loop.run(move |event, target| {
// Anordnung der Seiten gehört zum offenen Notizbuch (Issue #30)
ui_state.continuous_scroll =
manifest.layout_or(ui_settings.continuous_scroll) == NotebookLayout::Continuous;
match event { match event {
Event::AboutToWait => { Event::AboutToWait => {
let prev_status = autosave.status(); let prev_status = autosave.status();
@@ -3562,11 +3565,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
window.request_redraw(); window.request_redraw();
} }
UiAction::CreateNotebook { title, folder } => { UiAction::CreateNotebook { title, folder, layout } => {
let _ = autosave.flush(); let _ = autosave.flush();
match storage::create_new_notebook(&storage_base_dir, &title) { match storage::create_new_notebook(&storage_base_dir, &title) {
Ok((new_nb, new_manifest, new_dir)) => { Ok((new_nb, mut new_manifest, new_dir)) => {
let id = new_manifest.id.clone(); let id = new_manifest.id.clone();
new_manifest.layout = Some(layout);
change_library(&storage_base_dir, &mut ui_state, |library| { change_library(&storage_base_dir, &mut ui_state, |library| {
library.move_notebook(&id, &folder) library.move_notebook(&id, &folder)
}); });
@@ -3576,6 +3580,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
notebook = new_nb; notebook = new_nb;
manifest = new_manifest; manifest = new_manifest;
storage_dir = new_dir; storage_dir = new_dir;
autosave.mark_manifest_dirty(&manifest);
selection_state.clear(); selection_state.clear();
ui_state.current_notebook_id = manifest.id.clone(); ui_state.current_notebook_id = manifest.id.clone();
ui_state.document_title = manifest.title.clone(); ui_state.document_title = manifest.title.clone();
@@ -3820,9 +3825,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
save_ui_settings(&ui_settings, ui_settings_path.as_deref(), &mut ui_state); save_ui_settings(&ui_settings, ui_settings_path.as_deref(), &mut ui_state);
window.request_redraw(); window.request_redraw();
} }
UiAction::SetContinuousScroll(on) => { UiAction::SetNotebookLayout(layout) => {
ui_settings.continuous_scroll = on; manifest.layout = Some(layout);
save_ui_settings(&ui_settings, ui_settings_path.as_deref(), &mut ui_state); ui_state.continuous_scroll = layout == NotebookLayout::Continuous;
autosave.mark_manifest_dirty(&manifest);
window.request_redraw(); window.request_redraw();
} }
UiAction::SaveStylusButtons => { UiAction::SaveStylusButtons => {
+2 -1
View File
@@ -212,7 +212,8 @@ pub struct UiSettings {
pub pattern_color: PatternColor, pub pattern_color: PatternColor,
/// Druckkennlinie des Stifts /// Druckkennlinie des Stifts
pub pressure_curve: PressureCurve, pub pressure_curve: PressureCurve,
/// Seiten durchgehend untereinander anzeigen (sonst einzeln blättern) /// Frühere globale Einstellung „Seiten durchgehend scrollen“: gilt nur noch für Notizbücher
/// ohne eigene Anordnung im Manifest (vor 0.28 angelegt), wird nicht mehr geändert
pub continuous_scroll: bool, pub continuous_scroll: bool,
/// Stifte der Werkzeugleiste und der gewählte davon /// Stifte der Werkzeugleiste und der gewählte davon
pub pen_presets: [PenPreset; PEN_PRESET_COUNT], pub pen_presets: [PenPreset; PEN_PRESET_COUNT],
+49
View File
@@ -280,9 +280,32 @@ pub struct NotebookManifest {
pub page_ids: Vec<u64>, pub page_ids: Vec<u64>,
pub next_stroke_id: u64, pub next_stroke_id: u64,
pub next_page_id: u64, pub next_page_id: u64,
/// Anordnung der Seiten. Fehlt bei Notizbüchern von vor 0.28; dann gilt die frühere
/// globale Einstellung `continuous_scroll` aus `ui.json` (siehe [`Self::layout_or`]).
#[serde(default, skip_serializing_if = "Option::is_none")]
pub layout: Option<NotebookLayout>,
}
/// Anordnung der Seiten eines Notizbuchs (Issue #30).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum NotebookLayout {
/// Feste Seiten: Seite für Seite blättern
#[default]
Paged,
/// Seiten hängen untereinander und werden durchgehend gescrollt
Continuous,
} }
impl NotebookManifest { impl NotebookManifest {
/// Anordnung des Notizbuchs; ohne eigene Angabe die frühere globale Einstellung.
pub fn layout_or(&self, legacy_continuous: bool) -> NotebookLayout {
self.layout.unwrap_or(if legacy_continuous {
NotebookLayout::Continuous
} else {
NotebookLayout::Paged
})
}
pub fn new(id: impl Into<String>, title: impl Into<String>) -> Self { pub fn new(id: impl Into<String>, title: impl Into<String>) -> Self {
let now = std::time::SystemTime::now() let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH) .duration_since(std::time::UNIX_EPOCH)
@@ -299,6 +322,7 @@ impl NotebookManifest {
page_ids: vec![1], page_ids: vec![1],
next_stroke_id: 1, next_stroke_id: 1,
next_page_id: 2, next_page_id: 2,
layout: Some(NotebookLayout::Paged),
} }
} }
@@ -1604,6 +1628,31 @@ mod tests {
assert!(shutdown_res.is_ok()); assert!(shutdown_res.is_ok());
} }
#[test]
fn test_notebook_layout_is_saved_and_old_manifests_fall_back() {
let temp_dir = tempfile::tempdir().unwrap();
let (_nb, mut manifest, dir) = create_new_notebook(temp_dir.path(), "Layout").unwrap();
// Neue Notizbücher: feste Seiten, unabhängig von der früheren globalen Einstellung
assert_eq!(manifest.layout, Some(NotebookLayout::Paged));
assert_eq!(manifest.layout_or(true), NotebookLayout::Paged);
manifest.layout = Some(NotebookLayout::Continuous);
save_manifest(&dir, &manifest).unwrap();
let (_nb, loaded) = load_notebook(&dir).unwrap();
assert_eq!(loaded.layout, Some(NotebookLayout::Continuous));
// Manifest von vor 0.28 ohne `layout`: es gilt die globale Einstellung
let mut json: serde_json::Value =
serde_json::from_str(&fs::read_to_string(dir.join("manifest.json")).unwrap()).unwrap();
json.as_object_mut().unwrap().remove("layout");
let old: NotebookManifest = serde_json::from_value(json).unwrap();
assert_eq!(old.layout, None);
assert_eq!(old.layout_or(true), NotebookLayout::Continuous);
assert_eq!(old.layout_or(false), NotebookLayout::Paged);
// … und schreibt beim Speichern auch keins dazu
assert!(!serde_json::to_string(&old).unwrap().contains("\"layout\""));
}
#[test] #[test]
fn test_notebook_management() { fn test_notebook_management() {
let temp_dir = tempfile::tempdir().expect("Konnte temporäres Verzeichnis nicht anlegen"); let temp_dir = tempfile::tempdir().expect("Konnte temporäres Verzeichnis nicht anlegen");
+53 -14
View File
@@ -22,7 +22,7 @@ use crate::settings::{
PenPreset, PressureCurve, SidebarSide, DEFAULT_HIGHLIGHTER_COLORS, DEFAULT_PEN_PRESETS, PenPreset, PressureCurve, SidebarSide, DEFAULT_HIGHLIGHTER_COLORS, DEFAULT_PEN_PRESETS,
DEFAULT_TEXT_COLORS, PEN_PRESET_COUNT, DEFAULT_TEXT_COLORS, PEN_PRESET_COUNT,
}; };
use crate::storage::NotebookSummary; use crate::storage::{NotebookLayout, NotebookSummary};
use crate::text::{TextEditing, TextFont, TEXT_SIZES_PT}; use crate::text::{TextEditing, TextFont, TEXT_SIZES_PT};
use crate::{t, tn}; use crate::{t, tn};
@@ -263,6 +263,7 @@ pub enum UiAction {
CreateNotebook { CreateNotebook {
title: String, title: String,
folder: String, folder: String,
layout: NotebookLayout,
}, },
/// Ordnerverwaltung (siehe `library.rs`) /// Ordnerverwaltung (siehe `library.rs`)
CreateFolder { CreateFolder {
@@ -317,8 +318,8 @@ pub enum UiAction {
SaveStylusButtons, SaveStylusButtons,
/// Druckkurve speichern (gilt während des Ziehens bereits über `UiState::pressure_curve`) /// Druckkurve speichern (gilt während des Ziehens bereits über `UiState::pressure_curve`)
SavePressureCurve(PressureCurve), SavePressureCurve(PressureCurve),
/// Seiten durchgehend untereinander statt einzeln anzeigen (wird gespeichert) /// Anordnung der Seiten des offenen Notizbuchs (wird im Manifest gespeichert)
SetContinuousScroll(bool), SetNotebookLayout(NotebookLayout),
/// Farbe von Karos, Linien und Punkten (wird gespeichert, gilt auch für den Export) /// Farbe von Karos, Linien und Punkten (wird gespeichert, gilt auch für den Export)
SetPatternColor(PatternColor), SetPatternColor(PatternColor),
/// Bilddatei auf der aktuellen Seite einfügen /// Bilddatei auf der aktuellen Seite einfügen
@@ -364,6 +365,8 @@ pub struct UiState {
pub document_title: String, pub document_title: String,
pub available_notebooks: Vec<NotebookSummary>, pub available_notebooks: Vec<NotebookSummary>,
pub new_notebook_title_input: String, pub new_notebook_title_input: String,
/// Anordnung für das nächste neue Notizbuch
pub new_notebook_layout: NotebookLayout,
pub renaming_notebook_id: Option<String>, pub renaming_notebook_id: Option<String>,
/// Ordner der Notizbücher und der gerade angezeigte Ordner im Dokumenten-Manager /// Ordner der Notizbücher und der gerade angezeigte Ordner im Dokumenten-Manager
pub library: crate::library::Library, pub library: crate::library::Library,
@@ -483,6 +486,7 @@ impl Default for UiState {
document_title: t!("Standard-Notizbuch").to_string(), document_title: t!("Standard-Notizbuch").to_string(),
available_notebooks: Vec::new(), available_notebooks: Vec::new(),
new_notebook_title_input: String::new(), new_notebook_title_input: String::new(),
new_notebook_layout: NotebookLayout::Paged,
renaming_notebook_id: None, renaming_notebook_id: None,
library: crate::library::Library::default(), library: crate::library::Library::default(),
notebook_folder: String::new(), notebook_folder: String::new(),
@@ -1641,6 +1645,38 @@ fn page_title_list(ui: &mut egui::Ui, notebook: &Notebook) -> Option<usize> {
chosen chosen
} }
/// Auswahl der Seitenanordnung eines Notizbuchs. `true`, wenn sie geändert wurde.
fn layout_picker(ui: &mut egui::Ui, layout: &mut NotebookLayout) -> bool {
let mut changed = false;
ui.horizontal_wrapped(|ui| {
for (option, label, tooltip) in [
(
NotebookLayout::Paged,
t!("📄 Feste Seiten"),
t!("Seite für Seite blättern"),
),
(
NotebookLayout::Continuous,
t!("📜 Durchgehend"),
t!("Seiten hängen untereinander, Mausrad und Finger scrollen \
(Strg+Mausrad zoomt); wer unten auf der letzten Seite schreibt, \
bekommt automatisch eine neue Seite."),
),
] {
if ui
.selectable_label(*layout == option, label)
.on_hover_text(tooltip)
.clicked()
&& *layout != option
{
*layout = option;
changed = true;
}
}
});
changed
}
/// Auswahlknopf für eine Papierfarbe: Farbmuster und Name. /// Auswahlknopf für eine Papierfarbe: Farbmuster und Name.
fn paper_theme_button(ui: &mut egui::Ui, theme: PaperTheme, selected: bool) -> egui::Response { fn paper_theme_button(ui: &mut egui::Ui, theme: PaperTheme, selected: bool) -> egui::Response {
let response = ui.add_sized( let response = ui.add_sized(
@@ -3753,17 +3789,15 @@ pub fn render_ui(
} }
}); });
section(ui, t!("ANSICHT")); section(ui, t!("SEITEN DIESES NOTIZBUCHS"));
if ui let mut layout = if state.continuous_scroll {
.checkbox(&mut state.continuous_scroll, t!("Seiten durchgehend scrollen")) NotebookLayout::Continuous
.on_hover_text( } else {
t!("An: Seiten hängen untereinander, Mausrad und Finger scrollen \ NotebookLayout::Paged
(Strg+Mausrad zoomt); wer unten auf der letzten Seite schreibt, \ };
bekommt automatisch eine neue Seite.\nAus: Seite für Seite blättern."), if layout_picker(ui, &mut layout) {
) state.continuous_scroll = layout == NotebookLayout::Continuous;
.changed() actions.push(UiAction::SetNotebookLayout(layout));
{
actions.push(UiAction::SetContinuousScroll(state.continuous_scroll));
} }
section(ui, t!("ZOOM")); section(ui, t!("ZOOM"));
@@ -4098,6 +4132,7 @@ pub fn render_ui(
actions.push(UiAction::CreateNotebook { actions.push(UiAction::CreateNotebook {
title, title,
folder: folder.clone(), folder: folder.clone(),
layout: state.new_notebook_layout,
}); });
state.new_notebook_title_input.clear(); state.new_notebook_title_input.clear();
} else if folder_btn.clicked() { } else if folder_btn.clicked() {
@@ -4109,6 +4144,10 @@ pub fn render_ui(
} }
} }
}); });
ui.horizontal(|ui| {
ui.label(t!("Seiten:"));
layout_picker(ui, &mut state.new_notebook_layout);
});
ui.add_space(8.0); ui.add_space(8.0);
ui.separator(); ui.separator();