From 0b7cd68f8be778135694e237a3e5ec0352bc08eb Mon Sep 17 00:00:00 2001 From: reese <120700018+rosematcha@users.noreply.github.com> Date: Wed, 7 Oct 2026 05:52:12 -0500 Subject: [PATCH] fix(type): recolour selected type from the Color and Swatches panels (#364) With characters selected while editing type, a new foreground colour from the Color panel, the Swatches or the Color Picker now recolours them, as in Photoshop, within the editing session's history step. The HSB sliders now act only on an edit: their h/s/v round trip isn't exact, so comparing values rewrote the foreground every frame. --- crates/ui-egui/src/color_picker_ui.rs | 6 ++- crates/ui-egui/src/panels.rs | 69 +++++++++++++++++++++++++-- crates/ui-egui/src/type_tool.rs | 9 ++++ crates/ui-egui/src/type_tool_tests.rs | 46 ++++++++++++++++++ 4 files changed, 125 insertions(+), 5 deletions(-) diff --git a/crates/ui-egui/src/color_picker_ui.rs b/crates/ui-egui/src/color_picker_ui.rs index 2e74de9845..12e2c0c8c4 100644 --- a/crates/ui-egui/src/color_picker_ui.rs +++ b/crates/ui-egui/src/color_picker_ui.rs @@ -406,7 +406,11 @@ pub fn confirm(app: &mut PhotocraftApp, f: &Map) -> Result [u8; 4] { + let t = text(app, id); + let b = t.text.char_indices().nth(ci).map_or(t.text.len(), |(b, _)| b); + let mut at = 0; + for r in t.char_runs() { + if b < at + r.len { + return r.style.color.to_rgba8(); + } + at += r.len; + } + [0; 4] +} + +/// A new foreground colour recolours the selected characters only, inside the editing session's +/// history step; with nothing selected (a caret, or not editing) the type keeps its colour. +#[test] +fn foreground_colour_recolours_only_selected_type() { + let mut app = new_app(); + let id = + LayerId(app.run("type.create", json!({"text": "Hello world", "size": 40, "x": 300, "y": 420, "color": "#000000"})).unwrap()["layer"].as_u64().unwrap()); + app.run("tools.setColors", json!({"foreground": "#ff0000"})).unwrap(); + super::foreground_changed(&mut app); + assert_eq!(rgb_at(&app, id, 0), [0, 0, 0, 255], "not editing: unchanged"); + let edit = |caret, anchor| crate::state::TextEdit { + layer: id.0, + caret, + anchor, + session: "s".into(), + created: false, + dragging: false, + resize: None, + preedit: None, + }; + app.ui.text_edit = Some(edit(3, 3)); + super::foreground_changed(&mut app); + assert_eq!(rgb_at(&app, id, 0), [0, 0, 0, 255], "a caret: unchanged"); + let steps = app.session.active().unwrap().history.entries().len(); + app.ui.text_edit = Some(edit(11, 6)); + super::foreground_changed(&mut app); + app.run("tools.setColors", json!({"foreground": "#00ff00"})).unwrap(); + super::foreground_changed(&mut app); + assert_eq!((rgb_at(&app, id, 0), rgb_at(&app, id, 5)), ([0, 0, 0, 255], [0, 0, 0, 255])); + assert_eq!((rgb_at(&app, id, 6), rgb_at(&app, id, 10)), ([0, 255, 0, 255], [0, 255, 0, 255])); + assert_eq!(app.session.active().unwrap().history.entries().len(), steps + 1, "one step for the session"); +}