UI: right-click a ruler to swap the document units
A right-click on either ruler (or the origin box) now opens a context menu listing the ten document units, the current one checked. Choosing one runs document.setUnits — the same one-undo-step change as Preferences ▸ Units ▸ General / Document Setup. The guide-drag interact on each ruler becomes click-and-drag so the same widget both drags out guides (left) and opens the unit menu (right); the origin box gets its own click interact. checked() reports the active unit so the menu shows the check-mark; the unit labels are already translated as the Units preference choices. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f12188ad15
commit
e6a3b37bed
|
|
@ -891,9 +891,14 @@ fn ruler_rects(full: egui::Rect) -> [egui::Rect; 3] {
|
|||
/// ruler, snapped as a moved guide is (with Shift to the ruler's ticks). Released anywhere else,
|
||||
/// it makes none.
|
||||
fn ruler_guides(app: &mut VectorcraftApp, ui: &Ui, full: egui::Rect, canvas: egui::Rect, xf: &Xf) {
|
||||
let [top, left, _] = ruler_rects(full);
|
||||
let [top, left, corner] = ruler_rects(full);
|
||||
// Right-click on a ruler or the origin box: the document units, to swap between them as
|
||||
// Preferences ▸ Units ▸ General does ([`crate::menus::ruler_menu_body`]).
|
||||
let mut unit_clicked = None;
|
||||
for (r, vertical, id) in [(top, false, "ruler-top"), (left, true, "ruler-left")] {
|
||||
let resp = ui.interact(r, egui::Id::new(id), Sense::drag());
|
||||
// Click-and-drag so the same widget drags out guides (left) and opens the unit menu (right).
|
||||
let resp = ui.interact(r, egui::Id::new(id), Sense::click_and_drag());
|
||||
resp.context_menu(|ui| crate::menus::ruler_menu_body(app, ui, &mut unit_clicked));
|
||||
let kind = if resp.drag_stopped() {
|
||||
PointerKind::Up
|
||||
} else if resp.dragged() {
|
||||
|
|
@ -912,6 +917,11 @@ fn ruler_guides(app: &mut VectorcraftApp, ui: &Ui, full: egui::Rect, canvas: egu
|
|||
app.status(e.to_string());
|
||||
}
|
||||
}
|
||||
let corner = ui.interact(corner, egui::Id::new("ruler-corner"), Sense::click());
|
||||
corner.context_menu(|ui| crate::menus::ruler_menu_body(app, ui, &mut unit_clicked));
|
||||
if let Some((id, p)) = unit_clicked {
|
||||
crate::menus::invoke(app, &id, p);
|
||||
}
|
||||
}
|
||||
|
||||
fn rulers(ui: &Ui, full: egui::Rect, xf: &Xf, hover: Option<Point>, unit: Unit, t: &Tokens) {
|
||||
|
|
|
|||
|
|
@ -1388,6 +1388,10 @@ pub fn checked(app: &VectorcraftApp, id: &str, p: &Value) -> Option<bool> {
|
|||
let cmyk = app.session.active().is_some_and(|d| d.doc.color_mode == vectorcraft_engine::doc::ColorMode::Cmyk);
|
||||
p.get("mode").and_then(Value::as_str) == Some(if cmyk { "cmyk" } else { "rgb" })
|
||||
}
|
||||
// The ruler context menu lists the document units, the current one checked.
|
||||
"document.setUnits" => {
|
||||
p.get("units").and_then(Value::as_str).and_then(vectorcraft_engine::doc::Unit::named) == Some(app.session.general_unit())
|
||||
}
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
|
@ -2559,6 +2563,21 @@ pub fn context_menu_body(app: &VectorcraftApp, ui: &mut egui::Ui, clicked: &mut
|
|||
});
|
||||
}
|
||||
|
||||
/// The document units a right-click on a ruler offers: each runs `document.setUnits`, exactly as
|
||||
/// Preferences ▸ Units ▸ General does, with the current one checked ([`checked`]).
|
||||
pub fn ruler_unit_items() -> Vec<Item> {
|
||||
vectorcraft_engine::doc::Unit::ALL.iter().map(|u| cp(u.label(), "document.setUnits", json!({ "units": u.label() }))).collect()
|
||||
}
|
||||
|
||||
/// The ruler context menu's popup (right-click a ruler or the origin box); the unit clicked goes in
|
||||
/// `clicked`, for [`invoke`].
|
||||
pub fn ruler_menu_body(app: &VectorcraftApp, ui: &mut egui::Ui, clicked: &mut Option<(String, Value)>) {
|
||||
widgets::menu_scroll(ui, |ui| {
|
||||
ui.set_min_width(160.0);
|
||||
render_items(app, ui, &ruler_unit_items(), true, clicked);
|
||||
});
|
||||
}
|
||||
|
||||
/// Render the menu bar.
|
||||
/// The in-window menu bar. Returns where its titles end (x): the bar itself takes the full width.
|
||||
pub fn menu_bar(app: &mut VectorcraftApp, ui: &mut egui::Ui) -> f32 {
|
||||
|
|
|
|||
|
|
@ -110,6 +110,32 @@ fn right_click_on_empty_canvas_offers_the_view_and_a_dismissing_click_does_nothi
|
|||
assert_eq!(app.session.active().unwrap().doc.art_bounds(), None);
|
||||
}
|
||||
|
||||
/// #: right-clicking a ruler offers the document units, the current one checked, and choosing one
|
||||
/// swaps them — the same effect as Preferences ▸ Units ▸ General (`document.setUnits`).
|
||||
#[test]
|
||||
fn right_clicking_a_ruler_swaps_the_document_units() {
|
||||
use vectorcraft_doc::Unit;
|
||||
let mut app = app();
|
||||
app.ui.view.rulers = true;
|
||||
let ctx = egui::Context::default();
|
||||
frame(&mut app, &ctx, vec![]);
|
||||
assert_eq!(app.session.general_unit(), Unit::Points, "a new document starts in the prefs unit");
|
||||
// Right-click on the top ruler (the band along the top, past the origin box).
|
||||
let texts = click(&mut app, &ctx, pos2(400.0, 8.0), PointerButton::Secondary);
|
||||
for label in ["Points", "Picas", "Inches", "Millimeters", "Feet & Inches", "Pixels"] {
|
||||
assert!(has(&texts, label), "{label} in {texts:?}");
|
||||
}
|
||||
assert!(texts.iter().any(|(t, _)| t == "✓ Points"), "the current unit is checked: {texts:?}");
|
||||
// Choosing a unit runs document.setUnits and closes the menu.
|
||||
let mm = texts.iter().find(|(t, _)| t.trim_start_matches(['✓', ' ']) == "Millimeters").map(|(_, r)| r.center()).expect("Millimeters");
|
||||
let texts = click(&mut app, &ctx, mm, PointerButton::Primary);
|
||||
assert_eq!(app.session.general_unit(), Unit::Millimeters, "the ruler's unit changed");
|
||||
assert!(!has(&texts, "Inches"), "the menu closed");
|
||||
// The left ruler offers the same menu, now checking the new unit.
|
||||
let texts = click(&mut app, &ctx, pos2(8.0, 300.0), PointerButton::Secondary);
|
||||
assert!(texts.iter().any(|(t, _)| t == "✓ Millimeters"), "the left ruler reflects the current unit: {texts:?}");
|
||||
}
|
||||
|
||||
fn labels(items: &[Item]) -> Vec<&'static str> {
|
||||
items
|
||||
.iter()
|
||||
|
|
|
|||
Loading…
Reference in New Issue