Merge pull request #5583 from dotCooCoo/fix/global-edit-options-close

Global Edit: the options dropdowns close when Global Edit starts
This commit is contained in:
BFlat
2026-11-04 18:53:00 +07:00
committed by GitHub
4 changed files with 56 additions and 6 deletions
+4 -3
View File
@@ -142,9 +142,9 @@ const GLOBAL_EDIT_OPTIONS_WIDTH: f32 = 24.0;
/// page places the options in the Control panel as well as in Properties
/// (<https://helpx.adobe.com/illustrator/desktop/manage-objects/edit-objects/edit-similar-objects.html>).
/// It opens the Properties panel's Global Edit Options, which set the same session options, and is
/// off while Global Edit is on, as that panel's dropdown is. It sits after Recolor Artwork, ahead of
/// the X/Y/W/H fields that the bar leaves out when it runs short of room, and is left out only when
/// no room is left for it.
/// off and closed while Global Edit is on, as that panel's dropdown is. It sits after Recolor
/// Artwork, ahead of the X/Y/W/H fields that the bar leaves out when it runs short of room, and is
/// left out only when no room is left for it.
fn global_edit_options(app: &mut VectorcraftApp, ui: &mut Ui) {
if !crate::menus::enabled(app, "select.globalEdit") || ui.available_width() < GLOBAL_EDIT_OPTIONS_WIDTH {
return;
@@ -152,6 +152,7 @@ fn global_edit_options(app: &mut VectorcraftApp, ui: &mut Ui) {
let on = app.session.active().is_some_and(|d| d.global_edit.is_some());
let options = widgets::icon_button_enabled(ui, "chevron-down", tl!("Global Edit Options"), false, !on, GLOBAL_EDIT_OPTIONS_WIDTH);
egui::Popup::menu(&options)
.open_memory(crate::panels::properties::global_edit_options_open(&options, on))
.close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside)
.show(|ui| crate::panels::properties::global_edit_options(app, ui));
}
+7 -2
View File
@@ -1807,7 +1807,7 @@ fn the_control_bar_shows_the_distribute_buttons_for_two_or_more_objects() {
/// The Control bar shows the Global Edit Options dropdown while Start Global Edit can run. Its
/// options are the session's, which the Properties panel's dropdown also sets: Match Size from
/// the Control bar narrows the Results and the objects Start Global Edit takes. The dropdown is off
/// while Global Edit is on, and absent when the selection cannot start it.
/// and closed while Global Edit is on, and absent when the selection cannot start it.
#[test]
fn the_control_bar_shows_the_global_edit_options() {
crate::i18n::set_current(crate::i18n::Lang::EN);
@@ -1860,9 +1860,14 @@ fn the_control_bar_shows_the_global_edit_options() {
let nodes = frame(&mut app, vec![]);
let button = find(&nodes, "Global Edit Options").unwrap_or_else(|| panic!("Global Edit on: the dropdown still shows"));
assert!(button.is_disabled(), "the options are off while Global Edit is on");
let results = |nodes: &Nodes| nodes.iter().any(|(_, n)| n.label().or(n.value()).is_some_and(|t| t.starts_with("Result")));
assert!(!results(&nodes), "Global Edit starting closes the open options");
assert!(!results(&frame(&mut app, vec![])));
app.run("select.globalEdit", json!({})).unwrap();
frame(&mut app, vec![]);
assert!(!results(&frame(&mut app, vec![])), "the options stay closed once Global Edit stops");
// At any width the button either fits inside the bar or is left out, and a wider bar never
// leaves it out once a narrower one showed it.
app.run("select.globalEdit", json!({})).unwrap();
let mut seen = false;
for width in (600..=2400).step_by(10) {
let screen = egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(width as f32, 300.0));
+11 -1
View File
@@ -240,10 +240,20 @@ fn global_edit_row(app: &mut VectorcraftApp, ui: &mut Ui) {
crate::menus::invoke(app, "select.globalEdit", json!({}));
}
let options = widgets::icon_button_enabled(ui, "chevron-down", tl!("Global Edit Options"), false, !on, 20.0);
egui::Popup::menu(&options).close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside).show(|ui| global_edit_options(app, ui));
egui::Popup::menu(&options)
.open_memory(global_edit_options_open(&options, on))
.close_behavior(egui::PopupCloseBehavior::CloseOnClickOutside)
.show(|ui| global_edit_options(app, ui));
});
}
/// The open state for a Global Edit Options dropdown's popup: a click on the button toggles the
/// popup, and the popup is closed while Global Edit is on, including when Global Edit starts with
/// the popup open.
pub(crate) fn global_edit_options_open(options: &egui::Response, on: bool) -> Option<egui::SetOpenCommand> {
if on { Some(egui::SetOpenCommand::Bool(false)) } else { options.clicked().then_some(egui::SetOpenCommand::Toggle) }
}
/// The Global Edit Options: what else similar objects must share (Match), where they may lie (On
/// Artboards) and how many objects that takes now. The Control bar's Global Edit Options dropdown
/// shows them too.
@@ -135,6 +135,40 @@ fn start_global_edit_quick_action_and_escape() {
assert!(!tall(&mut app, vec![]).iter().any(|(t, _)| t == "Start Global Edit"), "type has no Global Edit");
}
/// The Quick Actions' Global Edit Options close when Global Edit starts while they are open, and
/// stay closed once it stops.
#[test]
fn global_edit_starting_closes_the_quick_action_options() {
crate::i18n::set_current(crate::i18n::Lang::EN);
let mut app = VectorcraftApp::new(Session::new(), Default::default());
app.run("file.new", json!({"width": 400, "height": 300})).unwrap();
let a = app.run("shape.rectangle", json!({"x": 20, "y": 20, "width": 40, "height": 40})).unwrap()["id"].clone();
app.run("shape.rectangle", json!({"x": 200, "y": 20, "width": 40, "height": 40})).unwrap();
app.run("select.set", json!({"ids": [a]})).unwrap();
let ctx = egui::Context::default();
ctx.enable_accesskit();
let frame = |app: &mut VectorcraftApp, events: Vec<Event>| {
let raw = egui::RawInput { screen_rect: Some(Rect::from_min_size(Pos2::ZERO, vec2(300.0, 700.0))), events, ..Default::default() };
let mut out = ctx.run_ui(raw, |ui| global_edit_row(app, ui));
out.textures_delta.clear();
out.platform_output.accesskit_update.map(|u| u.nodes).unwrap_or_default()
};
type Nodes = Vec<(egui::accesskit::NodeId, egui::accesskit::Node)>;
let results = |nodes: &Nodes| nodes.iter().any(|(_, n)| n.label().or(n.value()).is_some_and(|t| t.starts_with("Result")));
let nodes = frame(&mut app, vec![]);
let b = nodes.iter().find(|(_, n)| n.label() == Some("Global Edit Options")).and_then(|(_, n)| n.bounds()).unwrap_or_else(|| panic!("{nodes:?}"));
let at = Pos2::new(((b.x0 + b.x1) / 2.0) as f32, ((b.y0 + b.y1) / 2.0) as f32);
let press = |pressed| Event::PointerButton { pos: at, button: PointerButton::Primary, pressed, modifiers: Default::default() };
frame(&mut app, vec![Event::PointerMoved(at), press(true)]);
frame(&mut app, vec![press(false)]);
assert!(results(&frame(&mut app, vec![])), "the options open");
app.run("select.globalEdit", json!({})).unwrap();
assert!(!results(&frame(&mut app, vec![])), "Global Edit starting closes the open options");
app.run("select.globalEdit", json!({})).unwrap();
frame(&mut app, vec![]);
assert!(!results(&frame(&mut app, vec![])), "the options stay closed once Global Edit stops");
}
/// The options' Results count is found once per document revision, options and selected
/// object, not every frame; another selected object or other options find it again.
#[test]