UI: platform shortcut notation in every label and tooltip (#251) (#262) (#262)

This commit is contained in:
TiredIsa 2026-10-06 01:14:50 +03:00 committed by GitHub
parent 07074634f6
commit 6266b7a96b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 154 additions and 65 deletions

View File

@ -573,7 +573,11 @@ fn curves(ui: &mut egui::Ui, v: &mut Value, cx: &EditorCx) -> Edit {
}
});
let t2 = Tokens::get(ui.ctx());
ui.label(RichText::new("Click to add a point · drag off or ⌘/Ctrl-click or Delete to remove").color(t2.text_faint).size(11.0));
ui.label(
RichText::new(format!("Click to add a point · drag off or {}-click or Delete to remove", crate::shortcuts::pretty("Cmd")))
.color(t2.text_faint)
.size(11.0),
);
ui.data_mut(|d| d.insert_temp(state_id, st));
if changed {
v[key] = json!(pts.iter().map(|q| [q[0].round(), q[1].round()]).collect::<Vec<_>>());

View File

@ -963,6 +963,8 @@ fn start_screen(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
let recent: Vec<String> = if cfg!(target_arch = "wasm32") { Vec::new() } else { app.ui.recent_files.iter().take(HOME_RECENT).cloned().collect() };
let recent_h = if recent.is_empty() { 0.0 } else { 34.0 + recent.len() as f32 * HOME_RECENT_ROW };
let card = Rect::from_center_size(area.center(), egui::vec2(460.0, 330.0 + recent_h));
let new_label = crate::shortcuts::command_label(app, "New document…", "file.new");
let open_label = crate::shortcuts::command_label(app, "Open…", "file.open");
ui.scope_builder(egui::UiBuilder::new().max_rect(card), |ui| {
ui.vertical_centered(|ui| {
ui.horizontal(|ui| {
@ -981,10 +983,10 @@ fn start_screen(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
ui.horizontal(|ui| {
ui.add_space(((card.width() - 2.0 * 190.0 - 12.0) / 2.0).max(0.0));
ui.spacing_mut().item_spacing.x = 12.0;
if crate::widgets::primary_button(ui, "New document… ⌘N", 190.0).clicked() {
if crate::widgets::primary_button(ui, &new_label, 190.0).clicked() {
app.ui.open_dialog(crate::state::DialogKind::NewDocument, crate::state::UiState::new_document_fields());
}
if crate::widgets::secondary_button(ui, "Open… ⌘O", 190.0).clicked() {
if crate::widgets::secondary_button(ui, &open_label, 190.0).clicked() {
app.open_dialog_file();
}
});

View File

@ -217,11 +217,11 @@ pub fn properties(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
ui.spacing_mut().item_spacing.x = 6.0;
let pixel_grid = crate::view_cmds::checked(app, "view.show.pixelGrid").unwrap_or(false);
for (icon, tip, id, on) in [
("ruler", "Rulers (⌘R)", "view.rulers", app.ui.extras.rulers),
("grid-3x3", "Grid (⌘')", "view.show.grid", app.ui.extras.grid),
("grid-2x2", "Pixel Grid", "view.show.pixelGrid", pixel_grid),
("ruler", crate::shortcuts::tip_label(app, "Rulers", "view.rulers"), "view.rulers", app.ui.extras.rulers),
("grid-3x3", crate::shortcuts::tip_label(app, "Grid", "view.show.grid"), "view.show.grid", app.ui.extras.grid),
("grid-2x2", crate::shortcuts::tip_label(app, "Pixel Grid", "view.show.pixelGrid"), "view.show.pixelGrid", pixel_grid),
] {
if icons::button(ui, icon, 26.0, on, tip).clicked() {
if icons::button(ui, icon, 26.0, on, &tip).clicked() {
run.push((id.to_string(), Value::Null));
}
}
@ -240,9 +240,12 @@ pub fn properties(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
ui.horizontal(|ui| {
ui.add_space(8.0);
ui.spacing_mut().item_spacing.x = 6.0;
for (icon, tip, id) in [("eye", "Show Guides (⌘;)", "view.show.guides"), ("lock", "Lock Guides", "view.lockGuides")] {
for (icon, tip, id) in [
("eye", crate::shortcuts::tip_label(app, "Show Guides", "view.show.guides"), "view.show.guides"),
("lock", crate::shortcuts::tip_label(app, "Lock Guides", "view.lockGuides"), "view.lockGuides"),
] {
let on = if id == "view.lockGuides" { app.ui.extras.lock_guides } else { app.ui.extras.guides };
if icons::button(ui, icon, 26.0, on, tip).clicked() {
if icons::button(ui, icon, 26.0, on, &tip).clicked() {
run.push((id.to_string(), Value::Null));
}
}

View File

@ -160,11 +160,11 @@ pub fn indicators(
actions.push(("layer.setEffectsExpanded".into(), json!({"layer": l.id.0, "expanded": !fx_open, "all": all})));
}
let (verb, name) = (if fx_open { "Collapse" } else { "Expand" }, l.name.clone());
let resp = resp.on_hover_text(if fx_open {
"Hide the layer's effects (⌥-click: all layers)"
} else {
"Show the layer's effects (⌥-click: all layers)"
});
let resp = resp.on_hover_text(format!(
"{} the layer's effects ({}-click: all layers)",
if fx_open { "Hide" } else { "Show" },
crate::shortcuts::pretty("Alt")
));
resp.widget_info(|| egui::WidgetInfo::labeled(egui::WidgetType::Button, true, format!("{verb} effects {name}")));
}
}

View File

@ -62,7 +62,7 @@ pub fn disclosure(ui: &mut egui::Ui, row: Rect, x: &mut f32, l: &Layer, actions:
actions.push(("layer.setExpanded".into(), json!({"layer": l.id.0, "expanded": !g.expanded, "all": all})));
}
let (verb, name) = (if g.expanded { "Collapse" } else { "Expand" }, l.name.clone());
let resp = resp.on_hover_text(if g.expanded { "Collapse group (⌥-click: all groups)" } else { "Expand group (⌥-click: all groups)" });
let resp = resp.on_hover_text(format!("{} group ({}-click: all groups)", if g.expanded { "Collapse" } else { "Expand" }, crate::shortcuts::pretty("Alt")));
resp.widget_info(|| egui::WidgetInfo::labeled(egui::WidgetType::Button, true, format!("{verb} group {name}")));
clicked
}

View File

@ -143,7 +143,7 @@ pub fn show(app: &mut PhotocraftApp, ctx: &egui::Context) {
app.ui.palette_open = false;
}
ui.add_space(4.0);
ui.label(RichText::new("↑↓ navigate ↵ run esc close").small().color(t.text_faint));
ui.label(RichText::new(format!("↑↓ navigate {} run esc close", crate::shortcuts::pretty("Enter"))).small().color(t.text_faint));
ui.data_mut(|d| {
d.insert_temp(qid, q);
d.insert_temp(sel_id, sel);

View File

@ -311,7 +311,8 @@ pub fn title_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
app.ui.workspace = ws;
crate::menus::apply_workspace(app);
}
if icons::button(ui, "search", 28.0, app.ui.palette_open, "Search commands (⌘K)").clicked() {
if icons::button(ui, "search", 28.0, app.ui.palette_open, &crate::shortcuts::tip_label(app, "Search commands", "edit.search")).clicked()
{
app.ui.palette_open = !app.ui.palette_open;
}
let theme_icon = if t.dark() { "sun" } else { "moon" };
@ -494,10 +495,10 @@ pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
Tool::RectMarquee | Tool::EllipseMarquee if t.pro => {
ui.spacing_mut().item_spacing.x = 2.0;
for (i, (icon, tip)) in [
("square", "New selection"),
("plus", "Add to selection (⇧)"),
("minus", "Subtract from selection (⌥)"),
("squares-subtract", "Intersect with selection (⇧⌥)"),
("square", "New selection".to_string()),
("plus", format!("Add to selection ({})", crate::shortcuts::pretty("Shift"))),
("minus", format!("Subtract from selection ({})", crate::shortcuts::pretty("Alt"))),
("squares-subtract", format!("Intersect with selection ({})", crate::shortcuts::pretty("Shift+Alt"))),
]
.iter()
.enumerate()
@ -546,7 +547,7 @@ pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
let _ = crate::menus::invoke(app, ui.ctx(), "select.selectAndMask", json!({}));
}
if app.ui.tool == Tool::PolygonLasso && !app.ui.polygon.is_empty() {
hint(ui, "Click the first point or press ↵ to close · Esc cancels");
hint(ui, &format!("Click the first point or press {} to close · Esc cancels", crate::shortcuts::pretty("Enter")));
}
}
Tool::MagicWand => {
@ -636,7 +637,9 @@ pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
let _ = icons::button(ui, "grid-3x3", 24.0, true, "Overlay: Rule of Thirds");
widgets::checkbox(ui, &mut o.crop_delete, "Delete Cropped Pixels");
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
if icons::button(ui, "check", 26.0, false, "Commit current crop operation (↵)").clicked() {
if icons::button(ui, "check", 26.0, false, &format!("Commit current crop operation ({})", crate::shortcuts::pretty("Enter")))
.clicked()
{
crate::canvas::commit_crop(app);
}
if icons::button(ui, "ban", 26.0, false, "Cancel current crop operation (Esc)").clicked() {
@ -681,12 +684,22 @@ pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
section(ui, "Distribute", "layer.distribute.");
});
}
Tool::RectMarquee | Tool::EllipseMarquee => hint(ui, "Drag to select · ⇧ add · ⌥ subtract · ⇧⌥ intersect · click to deselect"),
Tool::RectMarquee | Tool::EllipseMarquee => hint(
ui,
&format!(
"Drag to select · {} add · {} subtract · {} intersect · click to deselect",
crate::shortcuts::pretty("Shift"),
crate::shortcuts::pretty("Alt"),
crate::shortcuts::pretty("Shift+Alt")
),
),
Tool::Move => hint(ui, "Drag to move the active layer"),
Tool::Eyedropper => hint(ui, "Click to sample the foreground colour · ⌥-click for background"),
Tool::Eyedropper => {
hint(ui, &format!("Click to sample the foreground colour · {}-click for background", crate::shortcuts::pretty("Alt")))
}
Tool::Zoom => {
widgets::checkbox(ui, &mut app.ui.tool_options.zoom_scrubby, "Scrubby Zoom");
hint(ui, "Click to zoom in · ⌥-click to zoom out · drag right/left to zoom in/out");
hint(ui, &format!("Click to zoom in · {}-click to zoom out · drag right/left to zoom in/out", crate::shortcuts::pretty("Alt")));
if widgets::secondary_button(ui, "Fit Screen", 0.0).clicked()
&& let Some(i) = app.session.active_index()
{
@ -699,10 +712,22 @@ pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
}
}
Tool::Hand => hint(ui, "Drag to pan · hold Space with any tool"),
Tool::Lasso | Tool::PolygonLasso => hint(ui, "Drag (lasso) or click points (polygonal) · ⇧ add · ⌥ subtract"),
Tool::Lasso | Tool::PolygonLasso => hint(
ui,
&format!(
"Drag (lasso) or click points (polygonal) · {} add · {} subtract",
crate::shortcuts::pretty("Shift"),
crate::shortcuts::pretty("Alt")
),
),
Tool::Crop => hint(
ui,
"Drag a crop box · drag inside to move · edges resize (⇧ ratio, ⌥ centre) · Space moves while drawing · ↵ commits · Esc cancels",
&format!(
"Drag a crop box · drag inside to move · edges resize ({} ratio, {} centre) · Space moves while drawing · {} commits · Esc cancels",
crate::shortcuts::pretty("Shift"),
crate::shortcuts::pretty("Alt"),
crate::shortcuts::pretty("Enter")
),
),
Tool::Gradient => hint(ui, "Drag to draw a gradient"),
Tool::PaintBucket => hint(ui, "Click to fill similar colours"),
@ -1294,7 +1319,7 @@ fn layers(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
if icons::button(ui, "trash", 26.0, false, "Delete layer").clicked() {
actions.push(("layer.delete".into(), json!({})));
}
if icons::button(ui, "square-plus", 26.0, false, "Create a new layer (⇧⌘N)").clicked() {
if icons::button(ui, "square-plus", 26.0, false, &crate::shortcuts::tip_label(app, "Create a new layer", "layer.new.layer")).clicked() {
actions.push(("layer.new.layer".into(), json!({})));
}
if icons::button(ui, "folder", 26.0, false, "Create a new group").clicked() {
@ -1319,7 +1344,8 @@ fn layers(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
ui.close();
}
});
if icons::button(ui, "square-dot", 26.0, false, "Add a mask (from the selection; ⌥ inverts)").clicked() {
if icons::button(ui, "square-dot", 26.0, false, &format!("Add a mask (from the selection; {} inverts)", crate::shortcuts::pretty("Alt"))).clicked()
{
let alt = ui.input(|i| i.modifiers.alt);
actions.push((crate::layer_menu_ui::add_mask_command(doc.selection.is_some(), alt).into(), json!({})));
}
@ -2252,10 +2278,10 @@ fn effect_rows(app: &mut PhotocraftApp, ui: &mut egui::Ui, l: &Layer, depth: usi
fn selection_mode_buttons(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
ui.spacing_mut().item_spacing.x = 2.0;
for (i, (icon, tip)) in [
("square", "New selection"),
("plus", "Add to selection (⇧)"),
("minus", "Subtract from selection (⌥)"),
("squares-subtract", "Intersect with selection (⇧⌥)"),
("square", "New selection".to_string()),
("plus", format!("Add to selection ({})", crate::shortcuts::pretty("Shift"))),
("minus", format!("Subtract from selection ({})", crate::shortcuts::pretty("Alt"))),
("squares-subtract", format!("Intersect with selection ({})", crate::shortcuts::pretty("Shift+Alt"))),
]
.iter()
.enumerate()

View File

@ -319,7 +319,7 @@ pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
}
}
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
if crate::widgets::primary_button(ui, "✓", 32.0).on_hover_text("Commit Perspective Warp (↩)").clicked() {
if crate::widgets::primary_button(ui, "✓", 32.0).on_hover_text(format!("Commit Perspective Warp ({})", crate::shortcuts::pretty("Enter"))).clicked() {
commit(app);
} else if crate::widgets::secondary_button(ui, "⊘", 32.0).on_hover_text("Cancel (Esc)").clicked() {
app.distort.perspective = None;

View File

@ -310,10 +310,7 @@ fn history_log(app: &mut PhotocraftApp) {
// ------------------------------------------------------------------ shortcuts
/// The shortcut in effect for a menu item: the user's override, else `default`.
pub fn effective_shortcut(app: &PhotocraftApp, id: &str, default: Option<&str>) -> Option<String> {
app.session.prefs().shortcut(id, default).map(str::to_string)
}
pub use crate::shortcuts::{default_shortcut, effective_shortcut};
/// Every shortcut-bearing command (engine registry plus shell commands): (id, label, menu path,
/// default shortcut), menu items first in Photoshop order.
@ -335,17 +332,6 @@ pub fn shortcut_items(app: &PhotocraftApp) -> Vec<(String, String, Vec<String>,
out
}
/// Default (unmodified) shortcut of a command id.
pub fn default_shortcut(id: &str) -> Option<String> {
crate::menus::UI_COMMANDS
.iter()
.find(|c| c.0 == id)
.and_then(|c| c.3)
.or_else(|| photocraft_engine::commands::find(id).and_then(|c| c.shortcut))
.or_else(|| crate::menu_catalog::CATALOG.iter().find(|c| c.3 == id).and_then(|c| c.2))
.map(str::to_string)
}
/// Text of a key press for the shortcut editor (`Cmd+Shift+K`), `None` for bare modifiers.
pub fn shortcut_text(key: egui::Key, m: egui::Modifiers) -> Option<String> {
let mut parts = Vec::new();

View File

@ -916,7 +916,7 @@ pub fn clone_source_panel(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
let set = cs.slots[i].source.is_some();
let tip = match cs.slots[i].source {
Some(s) => format!("Clone source {}: {:.0}, {:.0}", i + 1, s[0], s[1]),
None => format!("Clone source {} (⌥-click with Clone Stamp to set)", i + 1),
None => format!("Clone source {} ({}-click with Clone Stamp to set)", i + 1, crate::shortcuts::pretty("Alt")),
};
let r = crate::icons::button(ui, "stamp", 30.0, cs.active == i, &tip);
if set {
@ -933,7 +933,7 @@ pub fn clone_source_panel(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
match (slot.source, slot.layer.and_then(|l| app.session.active().and_then(|d| d.doc.layer(photocraft_doc::LayerId(l)).map(|x| x.name.clone())))) {
(Some(_), Some(l)) => format!("Source: {} : {l}", app.session.active().map(|d| d.doc.name.clone()).unwrap_or_default()),
(Some(_), None) => "Source: set".to_string(),
_ => "Source: not set (⌥-click with Clone Stamp)".to_string(),
_ => format!("Source: not set ({}-click with Clone Stamp)", crate::shortcuts::pretty("Alt")),
};
ui.label(egui::RichText::new(src_line).color(t.text_dim).size(11.0));
ui.add_space(4.0);

View File

@ -361,7 +361,7 @@ pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
s.solve(true);
}
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
if crate::widgets::primary_button(ui, "✓", 32.0).on_hover_text("Commit Puppet Warp (↩)").clicked() {
if crate::widgets::primary_button(ui, "✓", 32.0).on_hover_text(format!("Commit Puppet Warp ({})", crate::shortcuts::pretty("Enter"))).clicked() {
commit(app);
} else if crate::widgets::secondary_button(ui, "⊘", 32.0).on_hover_text("Cancel (Esc)").clicked() {
app.distort.puppet = None;

View File

@ -152,7 +152,7 @@ pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui, tool: Tool) -> bo
crate::widgets::dropdown(ui, "clone-sample", &mut o.clone_sample, &opts, 130.0);
if app.ui.clone_source.is_none() {
crate::widgets::vline(ui, 22.0);
opt(ui, "⌥-click to set the source");
opt(ui, &format!("{}-click to set the source", crate::shortcuts::pretty("Alt")));
}
}
Tool::Dodge | Tool::Burn => {
@ -182,7 +182,7 @@ pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui, tool: Tool) -> bo
Tool::QuickSelection => {
crate::widgets::checkbox(ui, &mut o.sample_all_layers, "Sample All Layers");
crate::widgets::checkbox(ui, &mut o.enhance_edge, "Enhance Edge");
opt(ui, "⌥ to subtract");
opt(ui, &format!("{} to subtract", crate::shortcuts::pretty("Alt")));
crate::widgets::vline(ui, 22.0);
if crate::widgets::secondary_button(ui, "Select Subject", 0.0).clicked() {
let _ = app.run("select.subject", json!({}));

View File

@ -33,7 +33,9 @@ pub fn parse(s: &str) -> Option<KeyboardShortcut> {
Some(KeyboardShortcut::new(mods, key?))
}
/// Human-readable form for menus.
/// Human-readable form for menus, tooltips and inline hints (`Cmd+Shift+N` → `⌘⇧N` on
/// macOS, `Ctrl+Shift+N` elsewhere). Works for lone keys too: `pretty("Alt")` is `⌥`/`Alt`,
/// `pretty("Enter")` is `↩`/`Enter`.
pub fn pretty(s: &str) -> String {
let mac = cfg!(target_os = "macos");
s.split('+')
@ -42,12 +44,48 @@ pub fn pretty(s: &str) -> String {
("Cmd", false) => "Ctrl".to_string(),
("Shift", true) => "⇧".to_string(),
("Alt", true) => "⌥".to_string(),
("Enter", true) => "↩".to_string(),
("Delete", true) => "⌫".to_string(),
(other, _) => other.to_string(),
})
.collect::<Vec<_>>()
.join(if mac { "" } else { "+" })
}
/// The command's effective shortcut in the platform's notation (`Ctrl+N`), or `None` when
/// the command has no binding (the user removed it in Edit › Keyboard Shortcuts).
pub fn shortcut_label(app: &PhotocraftApp, command: &str) -> Option<String> {
effective_shortcut(app, command, default_shortcut(command).as_deref()).map(|s| pretty(&s))
}
/// `label` followed by the command's effective shortcut (`New document… Ctrl+N`); bare
/// `label` when the binding was removed.
pub fn command_label(app: &PhotocraftApp, label: &str, command: &str) -> String {
shortcut_label(app, command).map_or_else(|| label.to_string(), |sc| format!("{label} {sc}"))
}
/// `label` with the command's effective shortcut in parentheses (`Rulers (Ctrl+R)`); bare
/// `label` when the binding was removed.
pub fn tip_label(app: &PhotocraftApp, label: &str, command: &str) -> String {
shortcut_label(app, command).map_or_else(|| label.to_string(), |sc| format!("{label} ({sc})"))
}
/// The shortcut in effect for a command: the user's override, else `default`.
pub fn effective_shortcut(app: &PhotocraftApp, id: &str, default: Option<&str>) -> Option<String> {
app.session.prefs().shortcut(id, default).map(str::to_string)
}
/// Default (unmodified) shortcut of a command id.
pub fn default_shortcut(id: &str) -> Option<String> {
crate::menus::UI_COMMANDS
.iter()
.find(|c| c.0 == id)
.and_then(|c| c.3)
.or_else(|| photocraft_engine::commands::find(id).and_then(|c| c.shortcut))
.or_else(|| crate::menu_catalog::CATALOG.iter().find(|c| c.3 == id).and_then(|c| c.2))
.map(str::to_string)
}
/// With ⇧ held the OS reports the shifted character as the logical key (US layout): ⇧; is `:`.
fn shifted(k: Key) -> Option<Key> {
Some(match k {
@ -325,6 +363,35 @@ mod tests {
assert!(!key_matches(&clear, Key::Backspace, cmd));
}
#[test]
fn pretty_uses_the_platform_notation() {
let mac = cfg!(target_os = "macos");
assert_eq!(pretty("Cmd+Shift+N"), if mac { "⌘⇧N" } else { "Ctrl+Shift+N" });
// Lone keys and inline-hint combos.
assert_eq!(pretty("Alt"), if mac { "⌥" } else { "Alt" });
assert_eq!(pretty("Shift+Alt"), if mac { "⇧⌥" } else { "Shift+Alt" });
assert_eq!(pretty("Enter"), if mac { "↩" } else { "Enter" });
assert_eq!(pretty("Cmd+Enter"), if mac { "⌘↩" } else { "Ctrl+Enter" });
}
#[test]
fn labels_show_the_effective_shortcut_in_platform_notation() {
let mut app = PhotocraftApp::new(photocraft_engine::Session::new(), Default::default());
let new = command_label(&app, "New document…", "file.new");
if cfg!(target_os = "macos") {
assert_eq!(new, "New document… ⌘N");
} else {
assert_eq!(new, "New document… Ctrl+N");
}
assert_eq!(tip_label(&app, "Rulers", "view.rulers"), format!("Rulers ({})", pretty("Cmd+R")));
// A user override is picked up…
app.session.prefs.edit(|p| p.shortcuts.insert("file.new".into(), "Cmd+Shift+N".into()));
assert_eq!(command_label(&app, "New document…", "file.new"), format!("New document… {}", pretty("Cmd+Shift+N")));
// …and a removed binding hides the shortcut entirely.
app.session.prefs.edit(|p| p.shortcuts.insert("file.new".into(), String::new()));
assert_eq!(command_label(&app, "New document…", "file.new"), "New document…");
}
#[test]
fn clipboard_events_become_pixel_shortcuts_outside_text() {
let ctx = egui::Context::default();

View File

@ -874,7 +874,7 @@ pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
}
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.add_space(8.0);
if crate::icons::button(ui, "check", 24.0, false, "Commit transform (↩)").clicked() {
if crate::icons::button(ui, "check", 24.0, false, &format!("Commit transform ({})", crate::shortcuts::pretty("Enter"))).clicked() {
commit(app);
}
if crate::icons::button(ui, "ban", 24.0, false, "Cancel transform (Esc)").clicked() {
@ -945,7 +945,7 @@ fn warp_options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui, w: &Warp) {
}
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.add_space(8.0);
if crate::icons::button(ui, "check", 24.0, false, "Commit warp (↩)").clicked() {
if crate::icons::button(ui, "check", 24.0, false, &format!("Commit warp ({})", crate::shortcuts::pretty("Enter"))).clicked() {
commit(app);
}
if crate::icons::button(ui, "ban", 24.0, false, "Cancel warp (Esc)").clicked() {

View File

@ -266,9 +266,9 @@ pub fn styles_panel(app: &mut PhotocraftApp, ui: &mut egui::Ui, paragraph: bool)
}
}
resp.on_hover_text(if id == 0 && !paragraph {
"No character style"
"No character style".to_string()
} else {
"Click to apply, ⌥-click to clear overrides, double-click for Style Options"
format!("Click to apply, {}-click to clear overrides, double-click for Style Options", crate::shortcuts::pretty("Alt"))
});
}
});

View File

@ -761,7 +761,7 @@ pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui) {
if app.ui.text_edit.is_some() {
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
ui.add_space(8.0);
if crate::icons::button(ui, "check", 24.0, false, "Commit any current edits (⌘↩)").clicked() {
if crate::icons::button(ui, "check", 24.0, false, &format!("Commit any current edits ({})", crate::shortcuts::pretty("Cmd+Enter"))).clicked() {
commit(app);
}
if crate::icons::button(ui, "ban", 24.0, false, "Cancel any current edits (Esc)").clicked() {

View File

@ -360,7 +360,7 @@ pub fn options_bar(app: &mut PhotocraftApp, ui: &mut egui::Ui, tool: Tool) -> bo
let opts = [("path".to_string(), "Path"), ("shape".to_string(), "Shape")];
crate::widgets::dropdown(ui, "pen-mode", &mut o.vector_mode, &opts, 80.0);
crate::widgets::vline(ui, 22.0);
lbl(ui, "Click: corner · Drag: smooth · Click first point: close · ↩ finish · Esc cancel");
lbl(ui, &format!("Click: corner · Drag: smooth · Click first point: close · {} finish · Esc cancel", crate::shortcuts::pretty("Enter")));
return true;
}
let mut mode = "shape".to_string();

View File

@ -292,12 +292,13 @@ pub fn windows(app: &mut PhotocraftApp, ctx: &egui::Context) {
if app.ui.shell.modifier_keys {
let mut close = false;
let mut s = app.ui.shell.clone();
let cmd = if cfg!(target_os = "macos") { "⌘" } else { "Ctrl" };
let alt = if cfg!(target_os = "macos") { "⌥" } else { "Alt" };
let cmd = crate::shortcuts::pretty("Cmd");
let shift = crate::shortcuts::pretty("Shift");
let alt = crate::shortcuts::pretty("Alt");
crate::analysis_ui::panel_window(app, ctx, "modifier-keys", "Modifier Keys", vec2(-420.0, 80.0), 150.0, |ui| {
close = crate::analysis_ui::title_row(ui, "Modifier Keys");
ui.horizontal(|ui| {
for (label, on) in [("⇧", &mut s.sticky_shift), (cmd, &mut s.sticky_command), (alt, &mut s.sticky_alt)] {
for (label, on) in [(&*shift, &mut s.sticky_shift), (&*cmd, &mut s.sticky_command), (&*alt, &mut s.sticky_alt)] {
if ui.add(egui::Button::new(RichText::new(label).size(14.0)).selected(*on).min_size(vec2(40.0, 30.0))).clicked() {
*on = !*on;
}