mirror of
https://github.com/storytold/photocraft.git
synced 2026-11-11 00:11:46 +00:00
Merge pull request #12164 from ElNeMeR70/fix/patch-sample-all-layers-default-on-12125
Patch tool: start Content-Aware Sample All Layers on (#12125)
This commit is contained in:
3 files changed
+97
-8
No files matched your search
@@ -0,0 +1,64 @@
|
||||
//! The Patch tool's Content-Aware Sample All Layers starts on (#12125): a fresh start and Reset
|
||||
//! Tool give the Patch tool Sample All Layers on while other tools stay off, and saved settings
|
||||
//! keep their stored value.
|
||||
|
||||
use serde_json::json;
|
||||
|
||||
use crate::PhotocraftApp;
|
||||
use crate::state::{SampleAllLayers, Tool, ToolOptions};
|
||||
|
||||
fn app() -> PhotocraftApp {
|
||||
let mut s = photocraft_engine::Session::new();
|
||||
s.execute("file.new", json!({"width": 16, "height": 16})).unwrap();
|
||||
PhotocraftApp::new(s, crate::Services::default())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn patch_sample_all_layers_starts_on_and_other_tools_start_off() {
|
||||
let defaults = SampleAllLayers::default();
|
||||
assert!(defaults.patch);
|
||||
assert!(defaults.get(Tool::Patch));
|
||||
for tool in Tool::ALL {
|
||||
if tool != Tool::Patch {
|
||||
assert!(!defaults.get(tool), "{tool:?} should default to Sample All Layers off");
|
||||
}
|
||||
}
|
||||
|
||||
let app = app();
|
||||
assert!(app.ui.tool_options.sample_all.patch);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reset_tool_restores_patch_sample_all_layers_to_on() {
|
||||
let mut app = app();
|
||||
let ctx = egui::Context::default();
|
||||
app.ui.tool = Tool::Patch;
|
||||
app.ui.tool_options.sample_all.patch = false;
|
||||
app.ui.tool_options.sample_all.magic_wand = true;
|
||||
|
||||
crate::menus::invoke(&mut app, &ctx, super::RESET, json!({})).unwrap();
|
||||
assert!(app.ui.tool_options.sample_all.patch, "Reset Tool restores Patch Sample All Layers to on");
|
||||
assert!(app.ui.tool_options.sample_all.magic_wand, "other tools keep their Sample All Layers setting");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn saved_settings_keep_stored_patch_sample_all_layers_value() {
|
||||
let saved_off: ToolOptions = serde_json::from_value(json!({
|
||||
"sample_all": {
|
||||
"patch": false,
|
||||
"magic_wand": true
|
||||
}
|
||||
}))
|
||||
.unwrap();
|
||||
assert!(!saved_off.sample_all.patch);
|
||||
assert!(saved_off.sample_all.magic_wand);
|
||||
|
||||
let missing_patch: ToolOptions = serde_json::from_value(json!({
|
||||
"sample_all": {
|
||||
"magic_wand": true
|
||||
}
|
||||
}))
|
||||
.unwrap();
|
||||
assert!(missing_patch.sample_all.patch);
|
||||
assert!(missing_patch.sample_all.magic_wand);
|
||||
}
|
||||
@@ -353,10 +353,10 @@ fn default_eyedropper_sample() -> String {
|
||||
}
|
||||
|
||||
/// Each tool's Sample All Layers (the Paint Bucket calls it All Layers). Photoshop keeps one per
|
||||
/// tool, all off by default: turning it on for the Magic Wand must not leave Blur or Smudge
|
||||
/// copying the composite onto the active layer (#5524). The Mixer Brush keeps its own with the
|
||||
/// brush (`MixerSettings`).
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
|
||||
/// tool, all off by default except the Patch tool's Content-Aware Sample All Layers (#5524,
|
||||
/// #12125): turning it on for the Magic Wand must not leave Blur or Smudge copying the composite
|
||||
/// onto the active layer. The Mixer Brush keeps its own with the brush (`MixerSettings`).
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct SampleAllLayers {
|
||||
pub magic_wand: bool,
|
||||
@@ -373,6 +373,25 @@ pub struct SampleAllLayers {
|
||||
pub smudge: bool,
|
||||
}
|
||||
|
||||
impl Default for SampleAllLayers {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
magic_wand: false,
|
||||
quick_selection: false,
|
||||
object_selection: false,
|
||||
paint_bucket: false,
|
||||
magic_eraser: false,
|
||||
spot_healing: false,
|
||||
patch: true,
|
||||
content_aware_move: false,
|
||||
remove: false,
|
||||
blur: false,
|
||||
sharpen: false,
|
||||
smudge: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SampleAllLayers {
|
||||
/// `tool`'s setting; false for a tool without the option.
|
||||
pub fn get(mut self, tool: Tool) -> bool {
|
||||
|
||||
@@ -159,10 +159,12 @@ pub fn reset_options(o: &mut ToolOptions, tool: Tool) {
|
||||
/// The serialized name of `tool`'s own Sample All Layers inside `sample_all`, if it has one: a
|
||||
/// tool preset stores that one alone, not the other tools' (#5524, #7356).
|
||||
pub fn sample_all_key(tool: Tool) -> Option<String> {
|
||||
let mut probe = crate::state::SampleAllLayers::default();
|
||||
*probe.slot(tool)? = true;
|
||||
let Ok(Value::Object(m)) = serde_json::to_value(probe) else { return None };
|
||||
m.into_iter().find(|(_, v)| v.as_bool() == Some(true)).map(|(k, _)| k)
|
||||
let base = crate::state::SampleAllLayers::default();
|
||||
let mut probe = base;
|
||||
let slot = probe.slot(tool)?;
|
||||
*slot = !*slot;
|
||||
let (Ok(Value::Object(b)), Ok(Value::Object(m))) = (serde_json::to_value(base), serde_json::to_value(probe)) else { return None };
|
||||
m.into_iter().find(|(k, v)| b.get(k) != Some(v)).map(|(k, _)| k)
|
||||
}
|
||||
|
||||
/// The [`ToolOptions`] fields `tool` shows, by their serialized names: what Reset Tool resets and
|
||||
@@ -370,3 +372,7 @@ mod tests {
|
||||
assert_eq!((keys.len(), distinct.len()), (12, 12), "one key per tool with the option");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../patch_sample_all_default_tests.rs"]
|
||||
mod patch_sample_all_default_tests;
|
||||
Reference in new issue
Block a user