mirror of
https://github.com/storytold/photocraft.git
synced 2026-11-11 00:11:46 +00:00
fresh_brush gave the Dodge tool the plain 20 px hard default at 10 % spacing. It now gets the reference's 65 px soft round at 25 % spacing after Reset Tool and Reset All Tools, and on its first pick. The Burn tool has the same measured tip, so both share TONING_TOOL_TIP.
This commit is contained in:
1 parent
4af62e8abb
commit
65bd584259
5 files changed
+131
-22
No files matched your search
@@ -88,19 +88,18 @@ fn reset_all_tools_gives_it_the_tip_active_or_picked_later() {
|
||||
assert_eq!(tip(&mut app), BURN_TIP, "picked after the reset");
|
||||
}
|
||||
|
||||
/// The Dodge tool shares the Burn tool's tip (#12684); the Sponge keeps the default.
|
||||
#[test]
|
||||
fn other_toning_tools_keep_their_tips() {
|
||||
for tool in [Tool::Dodge, Tool::Sponge] {
|
||||
let mut a = app();
|
||||
pick(&mut a, tool);
|
||||
scramble(&mut a);
|
||||
invoke(&mut a, "tool.reset", json!({}));
|
||||
assert_eq!(tip(&mut a), DEFAULT_TIP, "{tool:?}");
|
||||
// A first use still takes the current tip, as before.
|
||||
let mut a = app();
|
||||
pick(&mut a, Tool::Pencil);
|
||||
scramble(&mut a);
|
||||
pick(&mut a, tool);
|
||||
assert_eq!(tip(&mut a)[0], 57.0, "{tool:?}, first use");
|
||||
}
|
||||
fn the_sponge_tool_keeps_its_tip() {
|
||||
let mut a = app();
|
||||
pick(&mut a, Tool::Sponge);
|
||||
scramble(&mut a);
|
||||
invoke(&mut a, "tool.reset", json!({}));
|
||||
assert_eq!(tip(&mut a), DEFAULT_TIP);
|
||||
// A first use still takes the current tip, as before.
|
||||
let mut a = app();
|
||||
pick(&mut a, Tool::Pencil);
|
||||
scramble(&mut a);
|
||||
pick(&mut a, Tool::Sponge);
|
||||
assert_eq!(tip(&mut a)[0], 57.0, "first use");
|
||||
}
|
||||
@@ -41,10 +41,10 @@ pub fn sync_tool_brush(app: &mut PhotocraftApp) {
|
||||
// in Normal mode: each tool's Mode starts at Normal, so a Multiply Brush doesn't make the
|
||||
// first Pattern Stamp stroke multiply (or give Healing a mode its menu doesn't have).
|
||||
// The Art History Brush also starts at full opacity (#10263): its Opacity is its own.
|
||||
// The Background Eraser, the Healing Brush, the Burn tool and the Clone Stamp start with
|
||||
// their own measured tips instead, as the whole brush Reset Tool gives them (#11911,
|
||||
// #12099, #12671, #12601).
|
||||
None if matches!(tool, Tool::BackgroundEraser | Tool::Healing | Tool::Burn | Tool::CloneStamp) => fresh_brush(tool, ¤t),
|
||||
// The Background Eraser, the Healing Brush, the Burn and Dodge tools and the Clone Stamp
|
||||
// start with their own measured tips instead, as the whole brush Reset Tool gives them
|
||||
// (#11911, #12099, #12671, #12684, #12601).
|
||||
None if matches!(tool, Tool::BackgroundEraser | Tool::Healing | Tool::Burn | Tool::Dodge | Tool::CloneStamp) => fresh_brush(tool, ¤t),
|
||||
None => {
|
||||
let opacity = if tool == Tool::ArtHistoryBrush { BrushSettings::default().opacity } else { current.opacity };
|
||||
BrushSettings { smoothing: first_smoothing(), mode: photocraft_color::BlendMode::Normal, opacity, ..current }
|
||||
@@ -78,15 +78,16 @@ const BRUSH_TOOL_TIP: (f32, f32, f32) = (13.0, 0.0, 0.25);
|
||||
const BACKGROUND_ERASER_TIP: (f32, f32, f32) = (13.0, 1.0, 0.25);
|
||||
/// The Healing Brush's tip after Reset Tool (#12099): a 19 px hard round at 25 % spacing.
|
||||
const HEALING_BRUSH_TIP: (f32, f32, f32) = (19.0, 1.0, 0.25);
|
||||
/// The Burn tool's tip after Reset Tool (#12671): a 65 px soft round at 25 % spacing.
|
||||
const BURN_TOOL_TIP: (f32, f32, f32) = (65.0, 0.0, 0.25);
|
||||
/// The Burn and Dodge tools' tip after Reset Tool (#12671, #12684): a 65 px soft round at 25 %
|
||||
/// spacing.
|
||||
const TONING_TOOL_TIP: (f32, f32, f32) = (65.0, 0.0, 0.25);
|
||||
/// The Clone Stamp's tip after Reset Tool (#12601): a 21 px soft round at 25 % spacing.
|
||||
const CLONE_STAMP_TIP: (f32, f32, f32) = (21.0, 0.0, 0.25);
|
||||
|
||||
/// `tool`'s brush as it starts out (Reset Tool, #2825): the default brush at Photoshop's
|
||||
/// smoothing, with the session's own fields of `current`. The Brush tool's tip is
|
||||
/// [`BRUSH_TOOL_TIP`], the Background Eraser's [`BACKGROUND_ERASER_TIP`], the Healing Brush's
|
||||
/// [`HEALING_BRUSH_TIP`], the Burn tool's [`BURN_TOOL_TIP`], the Clone Stamp's
|
||||
/// [`HEALING_BRUSH_TIP`], the Burn and Dodge tools' [`TONING_TOOL_TIP`], the Clone Stamp's
|
||||
/// [`CLONE_STAMP_TIP`] with no smoothing; the other tools keep the default tip.
|
||||
pub(crate) fn fresh_brush(tool: Tool, current: &BrushSettings) -> BrushSettings {
|
||||
let mut brush = BrushSettings { smoothing: first_smoothing(), ..BrushSettings::default() };
|
||||
@@ -94,7 +95,7 @@ pub(crate) fn fresh_brush(tool: Tool, current: &BrushSettings) -> BrushSettings
|
||||
Tool::Brush => (brush.size, brush.hardness, brush.spacing) = BRUSH_TOOL_TIP,
|
||||
Tool::BackgroundEraser => (brush.size, brush.hardness, brush.spacing) = BACKGROUND_ERASER_TIP,
|
||||
Tool::Healing => (brush.size, brush.hardness, brush.spacing) = HEALING_BRUSH_TIP,
|
||||
Tool::Burn => (brush.size, brush.hardness, brush.spacing) = BURN_TOOL_TIP,
|
||||
Tool::Burn | Tool::Dodge => (brush.size, brush.hardness, brush.spacing) = TONING_TOOL_TIP,
|
||||
Tool::CloneStamp => {
|
||||
(brush.size, brush.hardness, brush.spacing) = CLONE_STAMP_TIP;
|
||||
brush.smoothing.amount = 0.0;
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
//! #12684: the Dodge tool starts, and comes back after Reset Tool, with the reference application's
|
||||
//! tip: a 65 px soft round (hardness 0 %, angle 0°, roundness 100 %) at 25 % spacing. Other tools'
|
||||
//! starting tips are unchanged.
|
||||
|
||||
use serde_json::json;
|
||||
|
||||
use crate::PhotocraftApp;
|
||||
use crate::control::{ControlRequest, handle};
|
||||
use crate::state::Tool;
|
||||
|
||||
fn app() -> PhotocraftApp {
|
||||
let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), crate::Services::default());
|
||||
app.run("file.new", json!({"width": 200, "height": 200})).unwrap();
|
||||
app.sync_views();
|
||||
app
|
||||
}
|
||||
|
||||
/// Run a menu command as the control channel does, then the frame's sync.
|
||||
fn invoke(app: &mut PhotocraftApp, id: &str, params: serde_json::Value) {
|
||||
let ctx = egui::Context::default();
|
||||
let (req, _rx) = ControlRequest::new("ui.menu.invoke", json!({"id": id, "params": params}));
|
||||
handle(app, &ctx, &req);
|
||||
app.sync_views();
|
||||
}
|
||||
|
||||
/// Pick `tool`, and swap its brush in as a frame does.
|
||||
fn pick(app: &mut PhotocraftApp, tool: Tool) {
|
||||
app.ui.tool = tool;
|
||||
crate::paint_mouse::sync_tool_brush(app);
|
||||
app.sync_views();
|
||||
}
|
||||
|
||||
/// Size, hardness, spacing, angle and roundness of the live brush, as `brush.get` reports them.
|
||||
fn tip(app: &mut PhotocraftApp) -> [f64; 5] {
|
||||
let b = app.run("brush.get", json!({})).unwrap();
|
||||
["size", "hardness", "spacing", "angle", "roundness"].map(|k| (b[k].as_f64().unwrap() * 1e4).round() / 1e4)
|
||||
}
|
||||
|
||||
/// A tip that is no tool's starting tip, so a reset has something to undo.
|
||||
fn scramble(app: &mut PhotocraftApp) {
|
||||
let b = &mut app.session.tools.brush;
|
||||
(b.size, b.hardness, b.spacing, b.angle, b.roundness) = (57.0, 0.4, 0.6, 30.0, 0.5);
|
||||
}
|
||||
|
||||
const DODGE_TIP: [f64; 5] = [65.0, 0.0, 0.25, 0.0, 1.0];
|
||||
const DEFAULT_TIP: [f64; 5] = [20.0, 1.0, 0.1, 0.0, 1.0];
|
||||
|
||||
#[test]
|
||||
fn reset_tool_gives_the_dodge_tool_a_65_px_soft_tip() {
|
||||
let mut app = app();
|
||||
pick(&mut app, Tool::Dodge);
|
||||
scramble(&mut app);
|
||||
invoke(&mut app, "tool.reset", json!({}));
|
||||
assert_eq!(tip(&mut app), DODGE_TIP);
|
||||
// The options-bar brush chip reads the live brush's rounded size.
|
||||
assert_eq!(app.session.tools.brush.size.round(), 65.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_first_use_starts_with_the_tip() {
|
||||
// No stored tool brushes, as on a fresh install: the Dodge tool's first pick, after another
|
||||
// tool's tip.
|
||||
let mut app = app();
|
||||
pick(&mut app, Tool::Pencil);
|
||||
scramble(&mut app);
|
||||
pick(&mut app, Tool::Dodge);
|
||||
assert_eq!(tip(&mut app), DODGE_TIP);
|
||||
// Its own tip is then kept across tool switches.
|
||||
app.session.tools.brush.size = 42.0;
|
||||
pick(&mut app, Tool::Pencil);
|
||||
pick(&mut app, Tool::Dodge);
|
||||
assert_eq!(tip(&mut app)[0], 42.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_all_tools_gives_it_the_tip_active_or_picked_later() {
|
||||
let mut app = app();
|
||||
pick(&mut app, Tool::Dodge);
|
||||
scramble(&mut app);
|
||||
invoke(&mut app, "tool.resetAll", json!({"confirmed": true}));
|
||||
assert_eq!(tip(&mut app), DODGE_TIP, "active");
|
||||
let mut app = self::app();
|
||||
pick(&mut app, Tool::Dodge);
|
||||
scramble(&mut app);
|
||||
pick(&mut app, Tool::Pencil);
|
||||
invoke(&mut app, "tool.resetAll", json!({"confirmed": true}));
|
||||
pick(&mut app, Tool::Dodge);
|
||||
assert_eq!(tip(&mut app), DODGE_TIP, "picked after the reset");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn the_sponge_tool_keeps_its_tip() {
|
||||
let mut a = app();
|
||||
pick(&mut a, Tool::Sponge);
|
||||
scramble(&mut a);
|
||||
invoke(&mut a, "tool.reset", json!({}));
|
||||
assert_eq!(tip(&mut a), DEFAULT_TIP);
|
||||
// A first use still takes the current tip, as before.
|
||||
let mut a = app();
|
||||
pick(&mut a, Tool::Pencil);
|
||||
scramble(&mut a);
|
||||
pick(&mut a, Tool::Sponge);
|
||||
assert_eq!(tip(&mut a)[0], 57.0, "first use");
|
||||
}
|
||||
@@ -1061,6 +1061,8 @@ mod pencil_shift_digit_opacity_tests;
|
||||
#[cfg(test)]
|
||||
mod doc_tab_menu_tests;
|
||||
#[cfg(test)]
|
||||
mod dodge_default_tip_tests;
|
||||
#[cfg(test)]
|
||||
mod layers_empty_area_menu_tests;
|
||||
#[cfg(test)]
|
||||
mod pencil_auto_erase_tooltip_tests;
|
||||
|
||||
@@ -474,6 +474,9 @@ fn releasing_a_sequential_dab_stroke_commits_what_a_replay_paints() {
|
||||
});
|
||||
h.state_mut().ui.tool = tool;
|
||||
h.run_steps(1);
|
||||
// A tool with its own starting tip (Dodge, #12684) paints with that, not the setup's
|
||||
// brush: give it the setup's tip, as the replay below has.
|
||||
h.state_mut().run("tools.setBrush", json!({"brush": {"size": 24, "hardness": 0.2, "spacing": 0.1}})).unwrap();
|
||||
move_to(&mut h, 40.0, 30.0);
|
||||
button(&mut h, 40.0, 30.0, true);
|
||||
for (x, y) in [(70.0, 40.0), (100.0, 55.0), (130.0, 50.0), (160.0, 70.0)] {
|
||||
|
||||
Reference in new issue
Block a user