mirror of
https://github.com/storytold/photocraft.git
synced 2026-10-17 20:59:43 +02:00
This commit is contained in:
parent
07074634f6
commit
6266b7a96b
|
|
@ -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<_>>());
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}")));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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!({}));
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user