mirror of
https://github.com/storytold/photocraft.git
synced 2026-11-11 00:11:46 +00:00
Make Selection: Rendering and Operation groups; the dialog's step is Selection Change (#12917)
The Pen's Make Selection dialog (canvas menu, options bar) now has Photoshop's layout: Rendering with Feather Radius in pixels and Anti-aliased, then Operation with New / Add to / Subtract from / Intersect with Selection as radio buttons. The last three are greyed out without a selection. The fields and params are the same as before. OK with New Selection names the step it added "Selection Change". Cmd/Ctrl+Enter, the Paths panel and the combining operations keep "Make Selection" (not measured).
This commit is contained in:
1 parent
de9add28b2
commit
8824661f47
2 files changed
+65
No files matched your search
@@ -1261,6 +1261,7 @@ fn pen_dialog(app: &mut PhotocraftApp, command: &str, label: &str, name: &str) {
|
||||
if command == "path.toSelection" {
|
||||
// OK deselects and hides the path, as ⌘↩ does (#6079).
|
||||
fields.insert("__deselectPath".into(), json!(true));
|
||||
fields.insert(MAKE_SELECTION.into(), json!(true));
|
||||
}
|
||||
if command == "path.fill" {
|
||||
let fg = app.session.tools.foreground;
|
||||
@@ -1281,6 +1282,63 @@ fn pen_dialog(app: &mut PhotocraftApp, command: &str, label: &str, name: &str) {
|
||||
spec_dialog(app, command, label, spec, fields);
|
||||
}
|
||||
|
||||
/// Marks the Make Selection dialog [`pen_dialog`] opens. It keeps the schema dialog's fields, so OK
|
||||
/// and Alt+Reset work as before; only the body is Photoshop's layout (#12917).
|
||||
const MAKE_SELECTION: &str = "__makeSelection";
|
||||
|
||||
/// The Make Selection operations, in Photoshop's order: (`path.toSelection` mode, label).
|
||||
const MAKE_SELECTION_OPERATIONS: [(&str, &str); 4] =
|
||||
[("replace", "New Selection"), ("add", "Add to Selection"), ("subtract", "Subtract from Selection"), ("intersect", "Intersect with Selection")];
|
||||
|
||||
/// Is this dialog the Make Selection dialog?
|
||||
pub(crate) fn owns_make_selection(fields: &serde_json::Map<String, Value>) -> bool {
|
||||
fields.contains_key(MAKE_SELECTION)
|
||||
}
|
||||
|
||||
/// Photoshop's Make Selection dialog: Rendering (Feather Radius, Anti-aliased) and Operation.
|
||||
/// Without a selection there is nothing to combine with, so only New Selection is available.
|
||||
pub(crate) fn make_selection_body(app: &PhotocraftApp, ui: &mut egui::Ui, f: &mut serde_json::Map<String, Value>) {
|
||||
let has_selection = app.session.active().is_some_and(|st| st.doc.selection.is_some());
|
||||
ui.spacing_mut().item_spacing.y = 6.0;
|
||||
crate::widgets::section_label(ui, tl!("Rendering"));
|
||||
crate::widgets::hairline(ui);
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(tl!("Feather Radius:"));
|
||||
let mut feather = f.get("feather").and_then(Value::as_f64).unwrap_or(0.0) as f32;
|
||||
crate::widgets::value_field(ui, &mut feather, 0.0..=250.0, "", 64.0).accessible_name(tl!("Feather Radius:"));
|
||||
ui.label(tl!("pixels"));
|
||||
// The schema dialog's rounding, so OK sends what it sent.
|
||||
f.insert("feather".into(), json!((feather * 10.0).round() / 10.0));
|
||||
});
|
||||
let mut anti_alias = f.get("antiAlias").and_then(Value::as_bool).unwrap_or(true);
|
||||
crate::widgets::checkbox(ui, &mut anti_alias, tl!("Anti-aliased"));
|
||||
f.insert("antiAlias".into(), json!(anti_alias));
|
||||
ui.add_space(4.0);
|
||||
crate::widgets::section_label(ui, tl!("Operation"));
|
||||
crate::widgets::hairline(ui);
|
||||
let mut mode = f.get("mode").and_then(Value::as_str).unwrap_or("replace").to_string();
|
||||
// A combining mode set from outside, or a selection gone while the dialog was open.
|
||||
if !has_selection {
|
||||
mode = "replace".into();
|
||||
}
|
||||
for (key, label) in MAKE_SELECTION_OPERATIONS {
|
||||
ui.add_enabled_ui(key == "replace" || has_selection, |ui| ui.radio_value(&mut mode, key.to_string(), tl!(label)));
|
||||
}
|
||||
f.insert("mode".into(), json!(mode));
|
||||
}
|
||||
|
||||
/// OK in the Make Selection dialog: a new selection is the History step Selection Change, as in
|
||||
/// Photoshop (#12917). ⌘↩, the Paths panel and the combining operations keep the engine's Make
|
||||
/// Selection (not measured). Only a step this run added is renamed: `revision` is from before it.
|
||||
pub(crate) fn name_make_selection_step(app: &mut PhotocraftApp, fields: &serde_json::Map<String, Value>, params: &Value, revision: Option<u64>) {
|
||||
if !owns_make_selection(fields) || params.get("mode").and_then(Value::as_str).is_some_and(|m| m != "replace") {
|
||||
return;
|
||||
}
|
||||
if let Some(st) = app.session.active_mut().filter(|st| Some(st.revision) != revision) {
|
||||
st.history.set_current_label("Selection Change");
|
||||
}
|
||||
}
|
||||
|
||||
/// The Pen options bar's Make Selection (Path mode, #5703): the canvas menu's Make Selection…
|
||||
/// dialog for the path being drawn (committed first, as the menu does) or the active path.
|
||||
pub(crate) fn make_selection(app: &mut PhotocraftApp) -> Result<(), String> {
|
||||
|
||||
@@ -357,6 +357,9 @@ fn command_body_more(app: &mut PhotocraftApp, ui: &mut egui::Ui, d: &Dialog, fie
|
||||
_ if crate::smart_filter_dialog::owns(fields) => crate::smart_filter_dialog::body(app, ui, fields),
|
||||
_ if crate::adjust_dialog::owns(fields) => crate::adjust_dialog::body(app, ui, fields),
|
||||
_ if crate::blur_pins::owns(fields) => crate::blur_pins::body(ui, fields),
|
||||
_ if crate::canvas_tool_menu::owns_make_selection(fields) => {
|
||||
first_field_focused(ui, id, |ui| crate::canvas_tool_menu::make_selection_body(app, ui, fields))
|
||||
}
|
||||
_ if fields.contains_key("__filter") => filter_body(app, ui, d, fields, id),
|
||||
_ if crate::new_guide_ui::owns(fields) => crate::new_guide_ui::body(ui, fields),
|
||||
_ if crate::equalize_ui::owns(fields) => crate::equalize_ui::body(ui, fields),
|
||||
@@ -1008,6 +1011,7 @@ fn confirm_generic_command(app: &mut PhotocraftApp, d: Dialog) -> Result<Value,
|
||||
return Err(e);
|
||||
}
|
||||
};
|
||||
let revision = app.session.active().map(|st| st.revision);
|
||||
let result = crate::actions::run_step_dialog(app, &d.fields, &cmd, params.clone());
|
||||
if let Ok(r) = &result {
|
||||
report_file_errors(app, &d, r);
|
||||
@@ -1020,6 +1024,9 @@ fn confirm_generic_command(app: &mut PhotocraftApp, d: Dialog) -> Result<Value,
|
||||
Some(p) if result.is_ok() && running => p.committing = true,
|
||||
_ => app.filter_preview = None,
|
||||
}
|
||||
if result.is_ok() && cmd == "path.toSelection" {
|
||||
crate::canvas_tool_menu::name_make_selection_step(app, &d.fields, ¶ms, revision);
|
||||
}
|
||||
if result.is_ok()
|
||||
&& cmd == "path.toSelection"
|
||||
&& d.fields.contains_key("__deselectPath")
|
||||
|
||||
Reference in new issue
Block a user