feat(pens): seven pens in the toolbar (Issue #56)
Pens 5-7 are stored in a new field, so versions before 0.44 still read the first four instead of resetting all settings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
14abadbd03
commit
3b0b4f51fb
5 files changed
+87
-15
No files matched your search
+1
-1
@@ -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).
|
||||
|
||||
@@ -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).
|
||||
|
||||
+2
-2
@@ -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;
|
||||
|
||||
+82
-10
@@ -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<PenPreset>,
|
||||
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(
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user