Merge pull request #2138 from dotCooCoo/fix/glowing-edges-raster-stylize

Effect menu: Glowing Edges moves to a Stylize submenu under Raster Effects
This commit is contained in:
BFlat
2026-10-16 04:19:23 +07:00
committed by GitHub
2 changed files with 49 additions and 8 deletions
+15 -8
View File
@@ -3504,13 +3504,16 @@ fn font_items(english_names: bool) -> Vec<Item> {
/// The raster effects' submenus of the Effect menu (the Photoshop-style effects, below the
/// vector effects): (submenu, the catalogue's menu path of its effects).
const RASTER_MENUS: [(&str, &[&str]); 8] = [
/// The raster Stylize submenu shares its path with the vector one and lists only the effects at
/// that path that [`vectorcraft_effects::PIXEL_EFFECTS`] names.
const RASTER_MENUS: [(&str, &[&str]); 9] = [
("Artistic", &["Effect", "Artistic"]),
("Blur", &["Effect", "Blur"]),
("Brush Strokes", &["Effect", "Brush Strokes"]),
("Distort", &["Effect", "Distort"]),
("Pixelate", &["Effect", "Pixelate"]),
("Sharpen", &["Effect", "Sharpen"]),
("Stylize", &["Effect", "Stylize"]),
("Texture", &["Effect", "Texture"]),
("Video", &["Effect", "Video"]),
];
@@ -3540,10 +3543,16 @@ fn effect_menu() -> Vec<Item> {
"Warp",
];
let top_level = |e: &vectorcraft_effects::EffectInfo| e.menu == ["Effect"] && order.contains(&e.label);
// An effect goes in the vector submenu its path names unless it is a Photoshop-style effect,
// which goes in the raster submenu of the same name when `RASTER_MENUS` has one (Stylize ›
// Glowing Edges).
let in_vector_menu =
|e: &vectorcraft_effects::EffectInfo| order.iter().any(|s| e.menu == ["Effect", *s]) && !vectorcraft_effects::PIXEL_EFFECTS.contains(&e.id);
// The effects whose catalogue menu path is `path`.
let items_at = |path: &[&str]| -> Vec<Item> {
// `vector` picks the ones for the vector submenu or the ones for the raster submenu.
let items_at = |path: &[&str], vector: bool| -> Vec<Item> {
cat.iter()
.filter(|e| e.menu == path)
.filter(|e| e.menu == path && in_vector_menu(e) == vector)
.map(|e| match e.defaults.as_object().is_some_and(|o| o.is_empty()) {
// No options (Effect → Pathfinder): apply directly, like Illustrator.
true => Item::Cmd(e.label, "effect.apply", json!({ "effect": e.id })),
@@ -3556,7 +3565,7 @@ fn effect_menu() -> Vec<Item> {
out.push(Item::Cmd(e.label, "effect.apply", json!({ "effect": e.id })));
continue;
}
let items = items_at(&["Effect", sub_name]);
let items = items_at(&["Effect", sub_name], true);
if items.is_empty() {
let placeholder = match sub_name {
"3D and Materials" => vec![todo("Extrude & Bevel…"), todo("Revolve…"), todo("Inflate…"), todo("Rotate…"), todo("Materials…")],
@@ -3583,7 +3592,7 @@ fn effect_menu() -> Vec<Item> {
let raster: Vec<Item> = RASTER_MENUS
.iter()
.filter_map(|(name, path)| {
let items = items_at(path);
let items = items_at(path, false);
(!items.is_empty()).then(|| sub(name, items))
})
.collect();
@@ -3593,9 +3602,7 @@ fn effect_menu() -> Vec<Item> {
out.extend(raster);
}
// Anything not placed above (future effects) still shows up.
let placed = |e: &vectorcraft_effects::EffectInfo| {
top_level(e) || order.iter().any(|s| e.menu == ["Effect", *s]) || RASTER_MENUS.iter().any(|(_, path)| e.menu == *path)
};
let placed = |e: &vectorcraft_effects::EffectInfo| top_level(e) || in_vector_menu(e) || RASTER_MENUS.iter().any(|(_, path)| e.menu == *path);
for e in cat.iter().filter(|e| !placed(e)) {
out.push(Item::Cmd(e.label, "effect.dialog", json!({ "effect": e.id })));
}
+34
View File
@@ -140,6 +140,40 @@ fn effect_menu_lists_the_texture_filters_between_sharpen_and_video() {
assert!(at("Sharpen") < at("Texture") && at("Texture") < at("Video"));
}
/// Effect › Stylize under Raster Effects, between Sharpen and Texture: Glowing Edges opens its
/// dialog.
#[test]
fn effect_menu_lists_glowing_edges_in_the_raster_stylize_between_sharpen_and_texture() {
let app = app();
let entries = menus::menu_entries(&app);
let at = |label: &str| entries.iter().position(|e| e.path[0] == "Effect" && e.label == label).unwrap();
let glowing = &entries[at("Glowing Edges…")];
assert_eq!(glowing.path, ["Effect", "Stylize"]);
assert_eq!(glowing.command.as_deref(), Some("effect.dialog"));
assert_eq!(glowing.params, json!({"effect": "stylize.glowingEdges"}));
assert!(at("Unsharp Mask…") < at("Glowing Edges…") && at("Glowing Edges…") < at("Craquelure…"));
}
/// The vector effects' Stylize keeps its six effects and leaves Glowing Edges out.
#[test]
fn effect_menu_keeps_glowing_edges_out_of_the_vector_stylize() {
let tree = menus::menu_tree();
let (_, effect) = tree.iter().find(|(t, _)| *t == "Effect").expect("Effect menu");
let raster = effect.iter().position(|i| matches!(i, Item::Header("Raster Effects"))).expect("Raster Effects");
let stylize: Vec<(usize, Vec<&str>)> = effect
.iter()
.enumerate()
.filter_map(|(i, it)| match it {
Item::Sub("Stylize", items) => Some((i, items.iter().filter_map(|c| if let Item::Cmd(l, ..) = c { Some(*l) } else { None }).collect())),
_ => None,
})
.collect();
assert_eq!(stylize.len(), 2);
assert!(stylize[0].0 < raster && raster < stylize[1].0);
assert_eq!(stylize[0].1, ["Round Corners…", "Scribble…", "Drop Shadow…", "Inner Glow…", "Outer Glow…", "Feather…"]);
assert_eq!(stylize[1].1, ["Glowing Edges…"]);
}
#[test]
fn library_submenus_are_disabled_placeholders() {
let app = app();