feat(colors): save own colors under the presets of the color popovers (Issue #56)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
haraldandClaude Opus 5.5 committed 2026-11-14 10:52:16 +01:00
1 parent 9dbe625eef
commit bb9bb58790
4 files changed
+73 -5

No files matched your search

+2
View File
@@ -1485,6 +1485,7 @@ pub fn run_with(
ui_state.set_eraser_radius_mm(ui_settings.eraser_radius_mm); ui_state.set_eraser_radius_mm(ui_settings.eraser_radius_mm);
ui_state.math.set_enabled(ui_settings.math_assist); ui_state.math.set_enabled(ui_settings.math_assist);
ui_state.touch_draw_enabled = ui_settings.touch_draw; ui_state.touch_draw_enabled = ui_settings.touch_draw;
ui_state.saved_colors = ui_settings.saved_colors.clone();
ui_state.select_pen(ui_settings.active_pen); ui_state.select_pen(ui_settings.active_pen);
ui_state.highlighter_colors = ui_settings.highlighter_colors; ui_state.highlighter_colors = ui_settings.highlighter_colors;
ui_state.select_highlighter_color(ui_settings.active_highlighter); ui_state.select_highlighter_color(ui_settings.active_highlighter);
@@ -5636,6 +5637,7 @@ pub fn run_with(
updated.text_colors = ui_state.text_colors; updated.text_colors = ui_state.text_colors;
updated.active_text_color = ui_state.active_text_color; updated.active_text_color = ui_state.active_text_color;
updated.eraser_radius_mm = ui_state.eraser_radius_mm; updated.eraser_radius_mm = ui_state.eraser_radius_mm;
updated.saved_colors.clone_from(&ui_state.saved_colors);
if updated != ui_settings { if updated != ui_settings {
ui_settings = updated; ui_settings = updated;
save_ui_settings( save_ui_settings(
+4
View File
@@ -108,6 +108,10 @@ pub const EN: &[(&str, &str)] = &[
("Dunkelgrau", "Dark gray"), ("Dunkelgrau", "Dark gray"),
("Dunkle Stiftfarben aufhellen", "Lighten dark pen colors"), ("Dunkle Stiftfarben aufhellen", "Lighten dark pen colors"),
("Eigene Farbe wählen", "Choose a custom color"), ("Eigene Farbe wählen", "Choose a custom color"),
("Meine Farbe", "My color"),
("➕ Farbe merken", "➕ Save color"),
("Diese Farbe aus „Meine Farben“ entfernen", "Remove this color from “My colors”"),
("Die aktuelle Farbe zu „Meine Farben“ hinzufügen", "Add the current color to “My colors”"),
("Ein Ordner kann nicht in sich selbst verschoben werden", "A folder cannot be moved into itself"), ("Ein Ordner kann nicht in sich selbst verschoben werden", "A folder cannot be moved into itself"),
("Ein-/Ausgabefehler: {e}", "I/O error: {e}"), ("Ein-/Ausgabefehler: {e}", "I/O error: {e}"),
("Eine Fläche ohne Rand: in alle Richtungen schreiben, verschieben und zoomen. Wechsel nur bei einer einzigen Seite ohne PDF bzw. zurück, solange alles im Startausschnitt liegt.", "One surface without edges: write, pan and zoom in every direction. Switching only works for a single page without a PDF, and back only while everything lies in the starting area."), ("Eine Fläche ohne Rand: in alle Richtungen schreiben, verschieben und zoomen. Wechsel nur bei einer einzigen Seite ohne PDF bzw. zurück, solange alles im Startausschnitt liegt.", "One surface without edges: write, pan and zoom in every direction. Switching only works for a single page without a PDF, and back only while everything lies in the starting area."),
+12
View File
@@ -217,6 +217,9 @@ pub struct StylusButton {
/// Höchstens so viele Stifttasten werden gemerkt. /// Höchstens so viele Stifttasten werden gemerkt.
pub const MAX_STYLUS_BUTTONS: usize = 4; pub const MAX_STYLUS_BUTTONS: usize = 4;
/// How many own colors fit under the presets of the color popovers (two rows)
pub const MAX_SAVED_COLORS: usize = 12;
/// Benutzereinstellungen der Oberfläche. /// Benutzereinstellungen der Oberfläche.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(default)] #[serde(default)]
@@ -257,6 +260,8 @@ pub struct UiSettings {
/// One finger draws instead of moving the page. On by default on Android, where phones /// One finger draws instead of moving the page. On by default on Android, where phones
/// usually have no pen (Issue #50) /// usually have no pen (Issue #50)
pub touch_draw: bool, pub touch_draw: bool,
/// Own colors under the presets of the color popovers (Issue #56)
pub saved_colors: Vec<[f32; 3]>,
} }
impl Default for UiSettings { impl Default for UiSettings {
@@ -286,6 +291,7 @@ impl Default for UiSettings {
storage_dir: None, storage_dir: None,
math_assist: false, math_assist: false,
touch_draw: cfg!(target_os = "android"), touch_draw: cfg!(target_os = "android"),
saved_colors: Vec::new(),
} }
} }
} }
@@ -333,6 +339,11 @@ impl UiSettings {
.active_text_color .active_text_color
.min(settings.text_colors.len() - 1); .min(settings.text_colors.len() - 1);
settings.stylus_buttons.truncate(MAX_STYLUS_BUTTONS); settings.stylus_buttons.truncate(MAX_STYLUS_BUTTONS);
settings.saved_colors.truncate(MAX_SAVED_COLORS);
for rgb in &mut settings.saved_colors {
let [r, g, b, _] = sanitized_color([rgb[0], rgb[1], rgb[2], 1.0], [0.0, 0.0, 0.0, 1.0]);
*rgb = [r, g, b];
}
settings settings
} }
@@ -412,6 +423,7 @@ mod tests {
storage_dir: Some(PathBuf::from("/home/pia/Nextcloud/ink-notes")), storage_dir: Some(PathBuf::from("/home/pia/Nextcloud/ink-notes")),
math_assist: true, math_assist: true,
touch_draw: true, touch_draw: true,
saved_colors: vec![[0.2, 0.4, 0.6], [1.0, 0.5, 0.0]],
}; };
settings.save_to(&path).unwrap(); settings.save_to(&path).unwrap();
assert_eq!(UiSettings::load_from(&path), settings); assert_eq!(UiSettings::load_from(&path), settings);
+55 -5
View File
@@ -20,7 +20,7 @@ use crate::file_picker::{FilePicker, PickerKind};
use crate::ruler::{Ruler, RulerHit}; use crate::ruler::{Ruler, RulerHit};
use crate::settings::{ 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, MAX_SAVED_COLORS, PEN_PRESET_COUNT,
}; };
use crate::storage::{NotebookLayout, NotebookSummary}; use crate::storage::{NotebookLayout, NotebookSummary};
use crate::text::{TextEditing, TextFont, TEXT_SIZES_PT}; use crate::text::{TextEditing, TextFont, TEXT_SIZES_PT};
@@ -446,6 +446,8 @@ pub struct UiState {
pub is_text_color_menu_open: bool, pub is_text_color_menu_open: bool,
/// Farbwähler in den Farb-Popovern aufgeklappt /// Farbwähler in den Farb-Popovern aufgeklappt
pub show_color_picker: bool, pub show_color_picker: bool,
/// „Meine Farben“ in the color popovers (Issue #56)
pub saved_colors: Vec<[f32; 3]>,
/// Kontextmenü nach langem Drücken (Einfügen an dieser Stelle) /// Kontextmenü nach langem Drücken (Einfügen an dieser Stelle)
pub context_menu: Option<ContextMenu>, pub context_menu: Option<ContextMenu>,
/// Laufendes Platzschaffen (Vorschau) /// Laufendes Platzschaffen (Vorschau)
@@ -575,6 +577,7 @@ impl Default for UiState {
active_text_color: 0, active_text_color: 0,
is_text_color_menu_open: false, is_text_color_menu_open: false,
show_color_picker: false, show_color_picker: false,
saved_colors: Vec::new(),
context_menu: None, context_menu: None,
space_drag: None, space_drag: None,
stylus_buttons: Vec::new(), stylus_buttons: Vec::new(),
@@ -1304,17 +1307,21 @@ fn autosave_status_style(status: AutosaveStatus) -> (egui::Color32, &'static str
fn color_editor( fn color_editor(
ui: &mut egui::Ui, ui: &mut egui::Ui,
presets: &[ColorPreset], presets: &[ColorPreset],
saved: &mut Vec<[f32; 3]>,
color: &mut [f32; 4], color: &mut [f32; 4],
picker_open: &mut bool, picker_open: &mut bool,
) -> bool { ) -> bool {
let same_rgb = |a: &[f32], b: &[f32]| {
a[..3]
.iter()
.zip(&b[..3])
.all(|(a, b)| (a - b).abs() < 0.01)
};
let mut changed = false; let mut changed = false;
ui.horizontal(|ui| { ui.horizontal(|ui| {
ui.spacing_mut().item_spacing = egui::vec2(8.0, 0.0); ui.spacing_mut().item_spacing = egui::vec2(8.0, 0.0);
for &(preset, label) in presets { for &(preset, label) in presets {
let is_sel = preset[..3] let is_sel = same_rgb(&preset, color);
.iter()
.zip(&color[..3])
.all(|(a, b)| (a - b).abs() < 0.01);
if color_circle_swatch(ui, preset, is_sel, crate::i18n::tr(label), 30.0).clicked() { if color_circle_swatch(ui, preset, is_sel, crate::i18n::tr(label), 30.0).clicked() {
*color = [preset[0], preset[1], preset[2], color[3]]; *color = [preset[0], preset[1], preset[2], color[3]];
changed = true; changed = true;
@@ -1331,6 +1338,46 @@ fn color_editor(
*picker_open = !*picker_open; *picker_open = !*picker_open;
} }
}); });
// My colors (Issue #56): kept for pen, highlighter and text alike
ui.add_space(6.0);
ui.horizontal_wrapped(|ui| {
ui.spacing_mut().item_spacing = egui::vec2(8.0, 6.0);
let mut remove = None;
for (i, rgb) in saved.iter().enumerate() {
let swatch = [rgb[0], rgb[1], rgb[2], 1.0];
let is_sel = same_rgb(rgb, color);
if color_circle_swatch(ui, swatch, is_sel, t!("Meine Farbe"), 30.0).clicked() {
*color = [rgb[0], rgb[1], rgb[2], color[3]];
changed = true;
}
if is_sel {
remove = Some(i);
}
}
if let Some(i) = remove {
if ui
.button(egui::RichText::new("🗑").size(16.0))
.on_hover_text(t!("Diese Farbe aus „Meine Farben“ entfernen"))
.clicked()
{
saved.remove(i);
}
} else if saved.len() < MAX_SAVED_COLORS {
let label = if saved.is_empty() {
t!("➕ Farbe merken")
} else {
"➕"
};
if ui
.button(label)
.on_hover_text(t!("Die aktuelle Farbe zu „Meine Farben“ hinzufügen"))
.clicked()
{
saved.push([color[0], color[1], color[2]]);
}
}
});
if *picker_open { if *picker_open {
ui.add_space(6.0); ui.add_space(6.0);
let [r, g, b] = [0, 1, 2].map(|i| (color[i].clamp(0.0, 1.0) * 255.0).round() as u8); let [r, g, b] = [0, 1, 2].map(|i| (color[i].clamp(0.0, 1.0) * 255.0).round() as u8);
@@ -4093,6 +4140,7 @@ pub fn render_ui(
if color_editor( if color_editor(
ui, ui,
&PEN_COLOR_PRESETS, &PEN_COLOR_PRESETS,
&mut state.saved_colors,
&mut state.pen_color, &mut state.pen_color,
&mut state.show_color_picker, &mut state.show_color_picker,
) { ) {
@@ -4274,6 +4322,7 @@ pub fn render_ui(
if color_editor( if color_editor(
ui, ui,
&HIGHLIGHTER_COLOR_PRESETS, &HIGHLIGHTER_COLOR_PRESETS,
&mut state.saved_colors,
&mut state.highlighter_color, &mut state.highlighter_color,
&mut state.show_color_picker, &mut state.show_color_picker,
) { ) {
@@ -4380,6 +4429,7 @@ pub fn render_ui(
if color_editor( if color_editor(
ui, ui,
&PEN_COLOR_PRESETS, &PEN_COLOR_PRESETS,
&mut state.saved_colors,
&mut color, &mut color,
&mut state.show_color_picker, &mut state.show_color_picker,
) { ) {