diff --git a/README.de.md b/README.de.md index 29399d6..a9a6951 100644 --- a/README.de.md +++ b/README.de.md @@ -22,7 +22,7 @@ Die Oberfläche gibt es auf Deutsch und Englisch; ink-notes folgt der Systemspra ## Funktionen ### Schreiben und Zeichnen -- **Vier Stifte** in der Werkzeugleiste, jeder mit eigener Farbe und Stärke (0,15–5 mm, mit Druckstärke). Ändert man Farbe oder Stärke, merkt sich der gewählte Stift das – auch über einen Neustart hinweg. **Textmarker** (halbtransparent, 4–8 mm) in vier Farben; innerhalb eines Strichs wird er nicht dunkler, erst ein neuer Strich deckt stärker. +- **Sieben Stifte** in der Werkzeugleiste, jeder mit eigener Farbe und Stärke (0,15–5 mm, mit Druckstärke). Ändert man Farbe oder Stärke, merkt sich der gewählte Stift das – auch über einen Neustart hinweg. **Textmarker** (halbtransparent, 4–8 mm) in vier Farben; innerhalb eines Strichs wird er nicht dunkler, erst ein neuer Strich deckt stärker. - **Eigene Farben:** Jede Farbe in der Werkzeugleiste (Stifte, Textmarker, Text) lässt sich anpassen – gewählte Farbe erneut antippen, eine Vorgabe oder mit 🎨 einen freien Farbton wählen. Die Leiste merkt sich die Farben. Am Bildschirm erscheinen sie genauso wie im PDF- und Bildexport. - **Glättung in zwei Stufen:** Während des Schreibens glättet ein 1€-Filter das Zittern, die Linie erscheint sofort. Beim Absetzen wird der Strich nachbearbeitet: Ecken (Knicke über 65°) bleiben erhalten und werden rund verbunden, der Druckverlauf wird geglättet, überflüssige Punkte entfallen, die Enden werden rund. - **Druckkurve** im ☰-Menü an den eigenen Stift anpassen (weicher/härter, Schwelle gegen Grundrauschen). diff --git a/README.md b/README.md index 67d81e2..2e130b0 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ The interface is available in English and German; ink-notes follows the system l ## Features ### Writing and drawing -- **Four pens** in the toolbar, each with its own color and width (0.15–5 mm, pressure-sensitive). When you change a pen's color or width, it remembers that – also across restarts. **Highlighter** (semi-transparent, 4–8 mm) in four colors; it does not get darker within one stroke, only a new stroke covers more strongly. +- **Seven pens** in the toolbar, each with its own color and width (0.15–5 mm, pressure-sensitive). When you change a pen's color or width, it remembers that – also across restarts. **Highlighter** (semi-transparent, 4–8 mm) in four colors; it does not get darker within one stroke, only a new stroke covers more strongly. - **Custom colors:** Every color in the toolbar (pens, highlighter, text) can be changed – tap the selected color again and pick a preset or any shade with 🎨. The toolbar remembers the colors. They look the same on screen as in PDF and image exports. - **Two-stage smoothing:** While you write, a 1€ filter removes jitter and the line appears immediately. When you lift the pen, the stroke is refined: corners (bends over 65°) are kept and drawn round, the pressure curve is smoothed, redundant points are dropped and the ends become round. - **Pressure curve** adjustable to your pen in the ☰ menu (softer/harder, threshold against base noise). diff --git a/src/app.rs b/src/app.rs index e617eac..85fb960 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1467,7 +1467,7 @@ pub fn run_with( ui_state.pattern_color = ui_settings.pattern_color; ui_state.pressure_curve = ui_settings.pressure_curve; ui_state.continuous_scroll = ui_settings.continuous_scroll; - ui_state.pen_presets = ui_settings.pen_presets; + ui_state.pen_presets = ui_settings.pens(); ui_state.stylus_buttons = ui_settings.stylus_buttons.clone(); ui_state.set_eraser_radius_mm(ui_settings.eraser_radius_mm); ui_state.math.set_enabled(ui_settings.math_assist); @@ -5594,7 +5594,7 @@ pub fn run_with( ui_state.sync_tool_colors(); if !egui_ctx.is_using_pointer() { let mut updated = ui_settings.clone(); - updated.pen_presets = ui_state.pen_presets; + updated.set_pens(ui_state.pen_presets); updated.active_pen = ui_state.active_pen; updated.highlighter_colors = ui_state.highlighter_colors; updated.active_highlighter = ui_state.active_highlighter; diff --git a/src/settings.rs b/src/settings.rs index 2c05785..60b3923 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -100,10 +100,16 @@ impl PenPreset { } } -/// Anzahl der Stifte in der Werkzeugleiste. -pub const PEN_PRESET_COUNT: usize = 4; +/// Anzahl der Stifte in der Werkzeugleiste (Issue #56: seven). +pub const PEN_PRESET_COUNT: usize = 7; -/// Standardstifte: Schwarz, Blau und Rot fein, Grün etwas kräftiger. +/// Pens stored in `pen_presets`. Versions before 0.44 expect exactly four there and would +/// reset all settings for any other length, so the further pens go to `more_pen_presets` and a +/// rollback keeps the first four. +pub const STORED_PEN_PRESETS: usize = 4; + +/// Standardstifte: Schwarz, Blau und Rot fein, Grün etwas kräftiger, dazu Violett, Orange und +/// Grau. pub const DEFAULT_PEN_PRESETS: [PenPreset; PEN_PRESET_COUNT] = [ PenPreset { color: [0.12, 0.12, 0.14, 1.0], @@ -121,6 +127,18 @@ pub const DEFAULT_PEN_PRESETS: [PenPreset; PEN_PRESET_COUNT] = [ color: [0.18, 0.65, 0.35, 1.0], width_mm: 0.8, }, + PenPreset { + color: [0.55, 0.25, 0.75, 1.0], + width_mm: 0.5, + }, + PenPreset { + color: [0.95, 0.55, 0.10, 1.0], + width_mm: 0.5, + }, + PenPreset { + color: [0.45, 0.45, 0.48, 1.0], + width_mm: 0.5, + }, ]; /// Farben des Textmarkers in der Werkzeugleiste (halbtransparent). @@ -215,8 +233,10 @@ pub struct UiSettings { /// 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, - /// Stifte der Werkzeugleiste und der gewählte davon - pub pen_presets: [PenPreset; PEN_PRESET_COUNT], + /// Stifte der Werkzeugleiste und der gewählte davon: the first four here, the others in + /// `more_pen_presets` (see [`STORED_PEN_PRESETS`]); use [`Self::pens`] + pub pen_presets: [PenPreset; STORED_PEN_PRESETS], + pub more_pen_presets: Vec, pub active_pen: usize, /// Eigene Farben von Textmarker und Text-Werkzeug und die gewählte davon pub highlighter_colors: [[f32; 4]; 4], @@ -248,7 +268,13 @@ impl Default for UiSettings { pattern_color: PatternColor::default(), pressure_curve: PressureCurve::default(), continuous_scroll: true, - pen_presets: DEFAULT_PEN_PRESETS, + pen_presets: [ + DEFAULT_PEN_PRESETS[0], + DEFAULT_PEN_PRESETS[1], + DEFAULT_PEN_PRESETS[2], + DEFAULT_PEN_PRESETS[3], + ], + more_pen_presets: DEFAULT_PEN_PRESETS[STORED_PEN_PRESETS..].to_vec(), active_pen: 0, highlighter_colors: DEFAULT_HIGHLIGHTER_COLORS, active_highlighter: 0, @@ -283,9 +309,12 @@ impl UiSettings { Err(_) => Self::default(), }; settings.pressure_curve = settings.pressure_curve.sanitized(); - for (preset, fallback) in settings.pen_presets.iter_mut().zip(DEFAULT_PEN_PRESETS) { - *preset = preset.sanitized(fallback); + let pens = settings.pens(); + let mut sanitized = DEFAULT_PEN_PRESETS; + for ((preset, pen), fallback) in sanitized.iter_mut().zip(pens).zip(DEFAULT_PEN_PRESETS) { + *preset = pen.sanitized(fallback); } + settings.set_pens(sanitized); settings.active_pen = settings.active_pen.min(PEN_PRESET_COUNT - 1); for (color, fallback) in settings .highlighter_colors @@ -307,6 +336,22 @@ impl UiSettings { settings } + /// All pens of the toolbar; pens missing in the file (older versions had four) are the + /// default pens. + pub fn pens(&self) -> [PenPreset; PEN_PRESET_COUNT] { + let mut pens = DEFAULT_PEN_PRESETS; + let stored = self.pen_presets.iter().chain(&self.more_pen_presets); + for (pen, stored) in pens.iter_mut().zip(stored) { + *pen = *stored; + } + pens + } + + pub fn set_pens(&mut self, pens: [PenPreset; PEN_PRESET_COUNT]) { + self.pen_presets.copy_from_slice(&pens[..STORED_PEN_PRESETS]); + self.more_pen_presets = pens[STORED_PEN_PRESETS..].to_vec(); + } + /// Speichert die Einstellungen atomar. pub fn save_to(&self, path: &Path) -> Result<(), StorageError> { storage::atomic_write_json(path, self) @@ -338,7 +383,14 @@ mod tests { pen_presets: [PenPreset { color: [0.5, 0.2, 0.7, 1.0], width_mm: 1.5, - }; PEN_PRESET_COUNT], + }; STORED_PEN_PRESETS], + more_pen_presets: vec![ + PenPreset { + color: [0.1, 0.6, 0.7, 1.0], + width_mm: 2.0, + }; + PEN_PRESET_COUNT - STORED_PEN_PRESETS + ], active_pen: 2, highlighter_colors: [[0.9, 0.5, 0.1, 0.35]; 4], active_highlighter: 3, @@ -372,6 +424,24 @@ mod tests { assert_eq!(UiSettings::load_from(&path), UiSettings::default()); } + #[test] + fn test_seven_pens_stay_readable_for_older_versions() { + // Versions before 0.44 read `pen_presets` as exactly four pens (Issue #56) + #[derive(Deserialize)] + struct OldSettings { + pen_presets: [PenPreset; 4], + } + let mut settings = UiSettings::default(); + let mut pens = DEFAULT_PEN_PRESETS; + pens[6].color = [0.3, 0.3, 0.9, 1.0]; + settings.set_pens(pens); + let json = serde_json::to_string(&settings).unwrap(); + let old: OldSettings = serde_json::from_str(&json).unwrap(); + assert_eq!(old.pen_presets[..], DEFAULT_PEN_PRESETS[..4]); + let back: UiSettings = serde_json::from_str(&json).unwrap(); + assert_eq!(back.pens(), pens); + } + #[test] fn test_old_settings_file_keeps_new_defaults() { // ui.json aus v0.3.x kennt nur die Seite der Werkzeugleiste @@ -397,7 +467,7 @@ mod tests { assert_eq!(curve.threshold, 0.0); // Ohne Stifte: die Standardstifte; unsinnige Stifte werden begrenzt - assert_eq!(settings.pen_presets, DEFAULT_PEN_PRESETS); + assert_eq!(settings.pens(), DEFAULT_PEN_PRESETS); assert_eq!(settings.active_pen, 0); std::fs::write( &path, @@ -414,6 +484,8 @@ mod tests { assert_eq!(settings.pen_presets[0].color, [1.0, 0.0, 0.5, 1.0]); assert_eq!(settings.pen_presets[0].width_mm, 5.0); assert_eq!(settings.pen_presets[1].width_mm, 0.15); + // Files from before 0.44 have four pens: the others are the default pens + assert_eq!(settings.pens()[4..], DEFAULT_PEN_PRESETS[4..]); // Eigene Farben: Textmarker bleibt halbtransparent, Text deckend std::fs::write( diff --git a/src/ui.rs b/src/ui.rs index df1bcc6..3529618 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -721,7 +721,7 @@ impl UiState { } /// Länge der längsten Farbpalette; so viel Platz hält die Leiste immer frei. - pub const MAX_PALETTE_LEN: usize = 5; + pub const MAX_PALETTE_LEN: usize = PEN_PRESET_COUNT; /// Vertical gap between toolbar buttons and the height of a divider line. pub const SIDEBAR_SPACING: f32 = 2.0; pub const SIDEBAR_DIVIDER: f32 = 3.0;