mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-03 17:25:28 +00:00
keymap: panel menus, toggles and aliases on craft-keymap 6e136c9
- The importer marks Panel Menus items as panel-menu entries. - Show/Hide commands and the other show-and-hide toggles are marked as toggles, so Show and Hide names match only them. - The Preferences alias names its submenu (Preferences: General…). - The import test checks an alias match (Exit).
This commit is contained in:
1 parent
506c429c65
commit
8e20bdfe2d
4 files changed
+36
-13
No files matched your search
Generated
+1
-1
@@ -827,7 +827,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-keymap"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/aiongg/craft-libs?rev=66f22029ba71dad29dcda156f01f680763aa6659#66f22029ba71dad29dcda156f01f680763aa6659"
|
||||
source = "git+https://github.com/aiongg/craft-libs?rev=6e136c9114d4461e791f0599c4976fc0c01e0048#6e136c9114d4461e791f0599c4976fc0c01e0048"
|
||||
dependencies = [
|
||||
"egui",
|
||||
"serde",
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ repository = "https://github.com/storytold/designcraft"
|
||||
# Shared writer; the immutable revision must be published before this consumer.
|
||||
craft-pdf = { git = "https://github.com/storytold/craft-libs", rev = "c3487320b2d1de657b860b3c8abb44e1f2b32bd8", version = "=0.1.0", default-features = false }
|
||||
# Shared keyboard bindings: chords, overrides, conflicts, egui dispatch.
|
||||
craft-keymap = { git = "https://github.com/aiongg/craft-libs", rev = "66f22029ba71dad29dcda156f01f680763aa6659", version = "=0.1.0", features = ["egui"] }
|
||||
craft-keymap = { git = "https://github.com/aiongg/craft-libs", rev = "6e136c9114d4461e791f0599c4976fc0c01e0048", version = "=0.1.0", features = ["egui"] }
|
||||
# internal
|
||||
designcraft-geom = { path = "crates/geom" }
|
||||
designcraft-color = { path = "crates/color" }
|
||||
|
||||
@@ -36,7 +36,7 @@ const PANEL_KEYS: &[(&str, &str)] = &[
|
||||
/// Other names shortcut sets use for a command (InDesign's feature names), by command id.
|
||||
const IMPORT_ALIASES: &[(&str, &str)] = &[
|
||||
("app.quit", "Exit"),
|
||||
("app.preferences", "General"),
|
||||
("app.preferences", "Preferences: General…"),
|
||||
("app.insertTableDialog", "Insert Table"),
|
||||
("view.togglePresentation", "Presentation"),
|
||||
("color.defaultFillStroke", "Apply Default Fill and Stroke Colors"),
|
||||
@@ -50,6 +50,11 @@ const IMPORT_ALIASES: &[(&str, &str)] = &[
|
||||
("window.previousDocument", "Previous Window"),
|
||||
];
|
||||
|
||||
/// Commands that show and hide something without "Show/Hide" in their label. A shortcut set may
|
||||
/// name a toggle by what it does now (`Hide Hidden Characters`); the importer matches such names
|
||||
/// only to toggles.
|
||||
const TOGGLES: &[&str] = &["view.hiddenCharacters", "view.tagMarkers"];
|
||||
|
||||
/// Extra menu paths for import, where an alias would leave two commands on one name: InDesign's
|
||||
/// Tools area has Apply Color, which is also `object.color`'s label.
|
||||
const IMPORT_PATHS: &[(&str, &[&str])] = &[("color.applyColor", &["Tools", "Apply Color"])];
|
||||
@@ -146,6 +151,7 @@ fn build_catalogue() -> Vec<Bindable> {
|
||||
continue;
|
||||
}
|
||||
let id = b.command.id.as_str();
|
||||
b.is_toggle = b.label.starts_with("Show/Hide ") || TOGGLES.contains(&id);
|
||||
b.aliases.extend(IMPORT_ALIASES.iter().filter(|(c, _)| *c == id).map(|(_, a)| a.to_string()));
|
||||
b.paths.extend(IMPORT_PATHS.iter().filter(|(c, _)| *c == id).map(|(_, p)| p.iter().map(|s| s.to_string()).collect()));
|
||||
}
|
||||
|
||||
@@ -145,20 +145,30 @@ fn strip_suffix_ignore_case<'a>(s: &'a str, suffix: &str) -> Option<&'a str> {
|
||||
}
|
||||
|
||||
/// The set as `craft_keymap::import` reads it. An area named `<menu> Menu` is that menu; the
|
||||
/// Tools area is the Tools menu, where items named `… Tool` select tools. Items of other areas
|
||||
/// (panel menus, text and tables, views) have no menu, so they match only by a one-segment name.
|
||||
/// The keys are read with Mac modifier names when any key in the set uses one.
|
||||
/// Tools area is the Tools menu, where items named `… Tool` select tools. Items of the Panel Menus
|
||||
/// area name their panel first (`Character: All Caps`) and match a command under that panel.
|
||||
/// Items of other areas (text and tables, views) have no menu, so they match only by a one-segment
|
||||
/// name. The keys are read with Mac modifier names when any key in the set uses one.
|
||||
fn foreign(set: &ParsedSet) -> ForeignSet {
|
||||
#[derive(Clone, Copy, Default)]
|
||||
struct Area<'a> {
|
||||
menu: Option<&'a str>,
|
||||
tools: bool,
|
||||
panel_menu: bool,
|
||||
}
|
||||
let flavor = Flavor::detect(set.items.iter().flat_map(|i| &i.entries).map(|e| e.keys.as_str()));
|
||||
let menus: Vec<(Option<&str>, bool)> = set
|
||||
let areas: Vec<Area> = set
|
||||
.areas
|
||||
.iter()
|
||||
.map(|a| {
|
||||
let a = a.trim();
|
||||
if a.eq_ignore_ascii_case("tools") {
|
||||
(Some(a), true)
|
||||
Area { menu: Some(a), tools: true, panel_menu: false }
|
||||
} else if a.eq_ignore_ascii_case("panel menus") {
|
||||
Area { panel_menu: true, ..Area::default() }
|
||||
} else {
|
||||
(strip_suffix_ignore_case(a, " menu").map(str::trim).filter(|m| !m.is_empty() && !m.contains(':')), false)
|
||||
let menu = strip_suffix_ignore_case(a, " menu").map(str::trim).filter(|m| !m.is_empty() && !m.contains(':'));
|
||||
Area { menu, ..Area::default() }
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
@@ -166,9 +176,12 @@ fn foreign(set: &ParsedSet) -> ForeignSet {
|
||||
.items
|
||||
.iter()
|
||||
.map(|item| {
|
||||
let (menu, tools) = item.area.and_then(|a| menus.get(a)).copied().unwrap_or((None, false));
|
||||
let mut entry = ForeignEntry::new(menu, item.name.split(": ").map(str::trim)).at_line(item.line);
|
||||
entry.is_tool = tools && strip_suffix_ignore_case(&item.name, " tool").is_some();
|
||||
let area = item.area.and_then(|a| areas.get(a)).copied().unwrap_or_default();
|
||||
let mut entry = ForeignEntry::new(area.menu, item.name.split(": ").map(str::trim)).at_line(item.line);
|
||||
if area.panel_menu {
|
||||
entry = entry.in_panel_menu();
|
||||
}
|
||||
entry.is_tool = area.tools && strip_suffix_ignore_case(&item.name, " tool").is_some();
|
||||
entry.keys = item.entries.iter().map(|e| ForeignKey::read(Some(&e.context), &e.keys, flavor)).collect();
|
||||
entry
|
||||
})
|
||||
@@ -313,6 +326,8 @@ mod tests {
|
||||
\tColor: Swatches --- Default: Shift+Ctrl+F2\r\n\
|
||||
Product area : Tools\r\n\
|
||||
\tPen Tool --- Default: Shift+Ctrl+F3\r\n\
|
||||
Product area : File Menu\r\n\
|
||||
\tExit --- Default: Ctrl+Alt+F12\r\n\
|
||||
garbage line without a separator\r\n";
|
||||
let r = menus::run_ui(&mut app, "window.importShortcuts", &json!({"text": set})).unwrap().unwrap();
|
||||
assert_eq!(r["set"], "My Set");
|
||||
@@ -343,9 +358,11 @@ mod tests {
|
||||
// A Window menu panel item and a Tools item apply to the panel and the tool.
|
||||
assert_eq!(crate::keys::shortcut(&app.keymap, &crate::keys::panel("swatches")).as_deref(), Some("Cmd+Shift+F2"));
|
||||
assert_eq!(crate::keys::shortcut(&app.keymap, &crate::keys::tool("pen")).as_deref(), Some("Cmd+Shift+F3"));
|
||||
// InDesign's name for a command, as an alias.
|
||||
assert_eq!(menus::shortcut_of(&app, "app.quit").as_deref(), Some("Cmd+Alt+F12"));
|
||||
// The numeric keypad key is bound as the main key of the same name, and reported.
|
||||
assert_eq!(r["approximated"][0]["item"], "File > Close", "{r}");
|
||||
assert_eq!(r["imported"], 6, "{r}");
|
||||
assert_eq!(r["imported"], 7, "{r}");
|
||||
// Reset Shortcuts is the way back.
|
||||
menus::run_ui(&mut app, "window.resetShortcuts", &json!({})).unwrap().unwrap();
|
||||
assert_eq!(menus::shortcut_of(&app, "app.palette").as_deref(), Some("Cmd+Enter"));
|
||||
|
||||
Reference in new issue
Block a user