mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-26 11:16:50 -06:00
Merge PR #1024: New Workspace: Capture Panel Locations and Menu Customization, as InDesign's
Conflicts: - crates/ui-egui/src/dialogs.rs: kept the branch's dialog code and added #1024's New Workspace width, Capture checkboxes and confirm params at the branch's indentation. - crates/ui-egui/src/i18n.rs, i18n/{ar,de,it,ja,ka,pt_br,uk}.rs: kept both sides.
This commit is contained in:
@@ -458,6 +458,7 @@ Newest first.
|
||||
- 2026-10-15: A page scrolled or jumped to shows its paper while its render is on its way, as in InDesign, instead of the black of its shadow.
|
||||
- 2026-10-15: Tab, Shift+Tab and Presentation hide the icon column's panel flyout and the classic floating panels too, as InDesign hides floating panels.
|
||||
- 2026-10-15: Layers panel: an object's row is renamed with a slow double-click (a second click on the selected row), as in InDesign; a quick double-click only selects it.
|
||||
- **2026-10-15** · New Workspace is InDesign's: Name, and Capture › Panel Locations and Menu Customization (the items hidden with Edit › Menus), both on by default; a workspace saved without panel locations leaves the panels where they are. No readiness percentage change.
|
||||
- **2026-10-14** · The Type tool draws a new text frame over a locked empty frame, as InDesign does, instead of turning the locked frame into a text frame. No readiness percentage change.
|
||||
- **2026-10-14** · 100% black shows as pure black on screen by default, as InDesign's Appearance of Black does out of the box (Display All Blacks as Rich Black); Preferences › Appearance of Black › Display All Blacks Accurately still shows it as the dark grey it prints, and a saved choice is kept. No readiness percentage change.
|
||||
- **2026-10-14** · Pathfinder keeps the frontmost object, as InDesign does: a photo placed over shapes and intersected with them shows through the shapes (it was dropped, and the shapes kept their black fill); Add, Exclude Overlap and Minus Back take the front object's fill too, Subtract still keeps the back one. No readiness percentage change.
|
||||
|
||||
@@ -2036,7 +2036,7 @@ pub fn show(app: &mut DesignApp, ctx: &egui::Context) {
|
||||
let available = (ctx.content_rect().size() - frame_margin - egui::vec2(16.0, 16.0)).max(egui::Vec2::splat(1.0));
|
||||
let preferred_width: f32 = match d.id.as_str() {
|
||||
"alert" => 440.0,
|
||||
"closeDocument" | "updateLink" | "deletePages" => 380.0,
|
||||
"closeDocument" | "updateLink" | "deletePages" | "newWorkspace" => 380.0,
|
||||
"newDocument" => 960.0,
|
||||
"numberingSection" => 560.0,
|
||||
crate::effects_dialog::ID => 720.0,
|
||||
@@ -2534,10 +2534,10 @@ pub fn show(app: &mut DesignApp, ctx: &egui::Context) {
|
||||
crate::rtl::label(ui, crate::i18n::tr(&app.ui.language, "Name:"));
|
||||
text_field(ui, &mut d, "name", 220.0);
|
||||
});
|
||||
crate::rtl::label(
|
||||
ui,
|
||||
egui::RichText::new(crate::i18n::tr(&app.ui.language, "Saves which bars show and where the panels are.")).size(10.5),
|
||||
);
|
||||
ui.add_space(6.0);
|
||||
crate::rtl::label(ui, egui::RichText::new(crate::i18n::tr(&app.ui.language, "Capture")).font(semibold(12.0)));
|
||||
check(ui, &mut d, "panelLocations", crate::i18n::tr(&app.ui.language, "Panel Locations"));
|
||||
check(ui, &mut d, "menuCustomization", crate::i18n::tr(&app.ui.language, "Menu Customization"));
|
||||
}
|
||||
"fittingOptions" => {
|
||||
check(ui, &mut d, "autoFit", crate::i18n::tr(&app.ui.language, "Auto-Fit"));
|
||||
@@ -3327,7 +3327,10 @@ pub fn confirm(app: &mut DesignApp) -> Result<Value, String> {
|
||||
doc["glyphFallback"] = json!(d.b("glyphFallback"));
|
||||
app.run("document.preferences", doc)
|
||||
}
|
||||
"newWorkspace" => app.run("window.newWorkspace", json!({"name": d.s("name")})),
|
||||
"newWorkspace" => app.run(
|
||||
"window.newWorkspace",
|
||||
json!({"name": d.s("name"), "panelLocations": d.b("panelLocations"), "menuCustomization": d.b("menuCustomization")}),
|
||||
),
|
||||
"deletePages" => {
|
||||
if d.b("dontShowAgain") {
|
||||
app.ui.skip_delete_pages_warning = true;
|
||||
|
||||
@@ -119,6 +119,8 @@ const TABLE: &[(&str, [&str; 5])] = &[
|
||||
"受影响的页面包含对象。仍要删除这些页面吗?",
|
||||
],
|
||||
),
|
||||
("Capture", ["Erfassen", "Capturer", "Capturar", "取り込み", "捕捉"]),
|
||||
("Panel Locations", ["Bedienfeldpositionen", "Emplacements des panneaux", "Ubicaciones de paneles", "パネルの位置", "面板位置"]),
|
||||
(
|
||||
"Bulleted & Numbered Lists",
|
||||
[
|
||||
|
||||
@@ -52,6 +52,8 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
("Don't show again", "عدم الإظهار مرة أخرى"),
|
||||
("The affected page contains objects. Delete the page anyway?", "تحتوي الصفحة المعنية على كائنات. هل تريد حذف الصفحة على أي حال؟"),
|
||||
("The affected pages contain objects. Delete the pages anyway?", "تحتوي الصفحات المعنية على كائنات. هل تريد حذف الصفحات على أي حال؟"),
|
||||
("Capture", "التقاط"),
|
||||
("Panel Locations", "مواضع اللوحات"),
|
||||
("Bulleted & Numbered Lists", "القوائم ذات التعداد النقطي والرقمي"),
|
||||
("Current Page Number", "رقم الصفحة الحالية"),
|
||||
("Apply Color (,)", "تطبيق اللون (,)"),
|
||||
|
||||
@@ -37,6 +37,8 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
("Don't show again", "Nicht mehr anzeigen"),
|
||||
("The affected page contains objects. Delete the page anyway?", "Die betroffene Seite enthält Objekte. Seite trotzdem löschen?"),
|
||||
("The affected pages contain objects. Delete the pages anyway?", "Die betroffenen Seiten enthalten Objekte. Seiten trotzdem löschen?"),
|
||||
("Capture", "Erfassen"),
|
||||
("Panel Locations", "Bedienfeldpositionen"),
|
||||
("Clear", "Löschen"),
|
||||
("Duplicate", "Duplizieren"),
|
||||
("Select All", "Alles auswählen"),
|
||||
|
||||
@@ -51,6 +51,8 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
("Don't show again", "Non mostrare più"),
|
||||
("The affected page contains objects. Delete the page anyway?", "La pagina interessata contiene oggetti. Eliminarla comunque?"),
|
||||
("The affected pages contain objects. Delete the pages anyway?", "Le pagine interessate contengono oggetti. Eliminarle comunque?"),
|
||||
("Capture", "Acquisisci"),
|
||||
("Panel Locations", "Posizioni pannelli"),
|
||||
("Bulleted & Numbered Lists", "Elenchi puntati e numerati"),
|
||||
("Current Page Number", "Numero di pagina corrente"),
|
||||
("Apply Color (,)", "Applica colore (,)"),
|
||||
|
||||
@@ -54,6 +54,8 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
("Don't show again", "今後表示しない"),
|
||||
("The affected page contains objects. Delete the page anyway?", "対象のページにはオブジェクトが含まれています。ページを削除しますか?"),
|
||||
("The affected pages contain objects. Delete the pages anyway?", "対象のページにはオブジェクトが含まれています。ページを削除しますか?"),
|
||||
("Capture", "取り込み"),
|
||||
("Panel Locations", "パネルの位置"),
|
||||
("Bulleted & Numbered Lists", "箇条書き"),
|
||||
("Apply Color (,)", "カラーを適用 (,)"),
|
||||
("Apply Gradient (.)", "グラデーションを適用 (.)"),
|
||||
|
||||
@@ -37,6 +37,8 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
("Don't show again", "აღარ აჩვენო"),
|
||||
("The affected page contains objects. Delete the page anyway?", "გვერდი შეიცავს ობიექტებს. მაინც წავშალო გვერდი?"),
|
||||
("The affected pages contain objects. Delete the pages anyway?", "გვერდები შეიცავს ობიექტებს. მაინც წავშალო გვერდები?"),
|
||||
("Capture", "შენახვა"),
|
||||
("Panel Locations", "პანელების მდებარეობა"),
|
||||
("Reverse Path", "ტრაექტორიის შებრუნება"),
|
||||
("Set Anchor", "საყრდენი წერტილის დაყენება"),
|
||||
("Clear", "გასუფთავება"),
|
||||
|
||||
@@ -54,6 +54,8 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
("Don't show again", "Não mostrar novamente"),
|
||||
("The affected page contains objects. Delete the page anyway?", "A página afetada contém objetos. Excluir a página mesmo assim?"),
|
||||
("The affected pages contain objects. Delete the pages anyway?", "As páginas afetadas contêm objetos. Excluir as páginas mesmo assim?"),
|
||||
("Capture", "Capturar"),
|
||||
("Panel Locations", "Locais dos painéis"),
|
||||
("Bulleted & Numbered Lists", "Listas com marcadores e numeradas"),
|
||||
("Show Hidden Characters", "Mostrar caracteres ocultos"),
|
||||
("Current Page Number", "Número da página atual"),
|
||||
|
||||
@@ -52,6 +52,8 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
("Don't show again", "Більше не показувати"),
|
||||
("The affected page contains objects. Delete the page anyway?", "Сторінка містить об’єкти. Усе одно видалити сторінку?"),
|
||||
("The affected pages contain objects. Delete the pages anyway?", "Сторінки містять об’єкти. Усе одно видалити сторінки?"),
|
||||
("Capture", "Зберегти"),
|
||||
("Panel Locations", "Розташування панелей"),
|
||||
("Bulleted & Numbered Lists", "Марковані й нумеровані списки"),
|
||||
("Current Page Number", "Номер поточної сторінки"),
|
||||
("Apply Color (,)", "Застосувати колір (,)"),
|
||||
|
||||
@@ -119,6 +119,13 @@ pub struct SavedWorkspace {
|
||||
/// The workspace's own icon column (see [`UiState::icon_groups`]).
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub icon_groups: Option<Vec<Vec<String>>>,
|
||||
/// Saved with New Workspace › Capture › Panel Locations off: choosing the workspace leaves the
|
||||
/// bars and panels where they are.
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
pub keep_panels: bool,
|
||||
/// New Workspace › Capture › Menu Customization: the menu items hidden with Edit › Menus.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub hidden_menu_items: Option<Vec<String>>,
|
||||
}
|
||||
|
||||
/// A missing on-by-default bool stays on. `bool::default` is false.
|
||||
|
||||
@@ -289,7 +289,12 @@ pub const UI_COMMANDS: &[(&str, &str, Option<&str>, &str)] = &[
|
||||
None,
|
||||
"{name: Advanced|Book|Digital Publishing|Essentials|Essentials Classic|Interactive for PDF|Printing and Proofing|Typography or a saved workspace}",
|
||||
),
|
||||
("window.newWorkspace", "New Workspace…", None, "{name} — saves the current bars and panel arrangement"),
|
||||
(
|
||||
"window.newWorkspace",
|
||||
"New Workspace…",
|
||||
None,
|
||||
"{name, panelLocations?: bool (default true: the bars and panels), menuCustomization?: bool (default true: the menu items hidden with Edit › Menus)} — saves the workspace",
|
||||
),
|
||||
("window.deleteWorkspace", "Delete Workspace…", None, "{name}"),
|
||||
("window.resetWorkspace", "Reset Workspace", None, "{} — back to the current workspace as saved (or its defaults)"),
|
||||
("window.brightness", "Interface Color Theme", None, "{brightness: dark|mediumDark|mediumLight|light|highContrast}"),
|
||||
@@ -1775,7 +1780,8 @@ fn run_ui_inner(app: &mut DesignApp, id: &str, p: &Value) -> Option<Result<Value
|
||||
"window.toolsDoubleColumn" => flag(&mut app.ui.tools_double_column),
|
||||
"window.newWorkspace" => {
|
||||
let Some(name) = p.get("name").and_then(Value::as_str).map(str::trim).filter(|n| !n.is_empty()) else {
|
||||
app.ui.dialog = Some(crate::dialogs::Dialog::new("newWorkspace", json!({"name": ""})));
|
||||
app.ui.dialog =
|
||||
Some(crate::dialogs::Dialog::new("newWorkspace", json!({"name": "", "panelLocations": true, "menuCustomization": true})));
|
||||
return Some(Ok(Value::Null));
|
||||
};
|
||||
let u = &app.ui;
|
||||
@@ -1792,6 +1798,8 @@ fn run_ui_inner(app: &mut DesignApp, id: &str, p: &Value) -> Option<Result<Value
|
||||
docking: u.docking.clone(),
|
||||
docking_hidden: u.docking_hidden.clone(),
|
||||
icon_groups: u.icon_groups.clone(),
|
||||
keep_panels: !p.get("panelLocations").and_then(Value::as_bool).unwrap_or(true),
|
||||
hidden_menu_items: p.get("menuCustomization").and_then(Value::as_bool).unwrap_or(true).then(|| u.hidden_menu_items.clone()),
|
||||
};
|
||||
app.ui.custom_workspaces.retain(|x| x.name != name);
|
||||
app.ui.custom_workspaces.push(w);
|
||||
@@ -1820,6 +1828,13 @@ fn run_ui_inner(app: &mut DesignApp, id: &str, p: &Value) -> Option<Result<Value
|
||||
app.ui.docking_opened = None;
|
||||
let name = p.get("name").and_then(Value::as_str).unwrap_or("Essentials");
|
||||
if let Some(w) = app.ui.custom_workspaces.iter().find(|w| w.name == name).cloned() {
|
||||
if let Some(hidden) = w.hidden_menu_items {
|
||||
app.ui.hidden_menu_items = hidden;
|
||||
}
|
||||
if w.keep_panels {
|
||||
app.ui.workspace = w.name;
|
||||
return Some(Ok(Value::Null));
|
||||
}
|
||||
app.ui.control_bar = w.control_bar;
|
||||
app.ui.task_bar = w.task_bar;
|
||||
app.ui.task_bar_pin = w.task_bar_pin;
|
||||
@@ -4785,6 +4800,41 @@ mod tests {
|
||||
assert_eq!(app.ui.workspace, "Essentials");
|
||||
}
|
||||
|
||||
/// New Workspace › Capture (Learn Skills Daily's InDesign course, 11:40): Panel Locations and
|
||||
/// Menu Customization, both on by default.
|
||||
#[test]
|
||||
fn new_workspace_captures_panel_locations_and_menu_customization() {
|
||||
let mut app = crate::DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
|
||||
// The dialog offers both, checked.
|
||||
run_ui(&mut app, "window.newWorkspace", &json!({})).unwrap().unwrap();
|
||||
let d = app.ui.dialog.take().unwrap();
|
||||
assert_eq!(
|
||||
(d.id.as_str(), d.fields["panelLocations"].clone(), d.fields["menuCustomization"].clone()),
|
||||
("newWorkspace", json!(true), json!(true))
|
||||
);
|
||||
// Both captured.
|
||||
app.ui.dock_tab = "swatches".into();
|
||||
app.ui.hidden_menu_items = vec!["Type/Glyphs".into()];
|
||||
run_ui(&mut app, "window.newWorkspace", &json!({"name": "All"})).unwrap().unwrap();
|
||||
// Menus only: choosing it leaves the panels where they are.
|
||||
app.ui.hidden_menu_items = vec!["Layout/Pages".into()];
|
||||
run_ui(&mut app, "window.newWorkspace", &json!({"name": "Menus", "panelLocations": false})).unwrap().unwrap();
|
||||
// Panels only: the menus stay as they are.
|
||||
app.ui.dock_tab = "layers".into();
|
||||
run_ui(&mut app, "window.newWorkspace", &json!({"name": "Panels", "menuCustomization": false})).unwrap().unwrap();
|
||||
app.ui.dock_tab = "properties".into();
|
||||
app.ui.hidden_menu_items.clear();
|
||||
run_ui(&mut app, "window.workspace", &json!({"name": "Menus"})).unwrap().unwrap();
|
||||
assert_eq!((app.ui.dock_tab.as_str(), app.ui.hidden_menu_items.clone()), ("properties", vec!["Layout/Pages".to_string()]));
|
||||
run_ui(&mut app, "window.workspace", &json!({"name": "Panels"})).unwrap().unwrap();
|
||||
assert_eq!((app.ui.dock_tab.as_str(), app.ui.hidden_menu_items.clone()), ("layers", vec!["Layout/Pages".to_string()]));
|
||||
run_ui(&mut app, "window.workspace", &json!({"name": "All"})).unwrap().unwrap();
|
||||
assert_eq!((app.ui.dock_tab.as_str(), app.ui.hidden_menu_items.clone()), ("swatches", vec!["Type/Glyphs".to_string()]));
|
||||
// A workspace saved before the options existed restores its panels.
|
||||
let old: crate::SavedWorkspace = serde_json::from_value(json!({"name": "Old", "dockTab": "pages"})).unwrap();
|
||||
assert!(!old.keep_panels && old.hidden_menu_items.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn essentials_classic_is_the_control_panel_and_iconic_groups() {
|
||||
let mut app = crate::DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
|
||||
|
||||
Reference in New Issue
Block a user