mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-31 15:49:42 +00:00
Numbering & Section Options opens as New Section on a page without one, as InDesign's
Chris Nielsen's "Numbering Page Sections" (4:43): with page 3 selected, the Pages panel menu's Numbering & Section Options opens InDesign's New Section window: Start Section checked, Automatic Page Numbering chosen and 1 offered in Start Page Numbering at, which stays editable. The window here was titled Numbering & Section Options, Start Section was off and the field showed the page's current number, greyed out. - Opened on a page that doesn't start a section, the window is New Section: Start Section on and 1 offered; on a section's first page it is Numbering & Section Options, as before. - Start Page Numbering at and Start Chapter Numbering at stay editable; typing a number chooses that option. - "New Section" translated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
87bfdb7fe2
commit
be0fbb75c0
9 files changed
+76
-5
No files matched your search
@@ -129,6 +129,7 @@ list) · [roadmap.md](docs/roadmap.md) (milestones, plan) · [parity-checklist.m
|
||||
|
||||
Newest first.
|
||||
|
||||
- **2026-10-14** · Numbering & Section Options opened on a page that doesn't start a section is New Section, as in InDesign: Start Section on, 1 offered, and the start numbers stay editable (typing one chooses it). No readiness percentage change.
|
||||
- **2026-10-12** · macOS Dock Quit uses the same unsaved-document prompts as window and menu Quit. Repeated requests keep the current answers; Cancel retains every tab and unsaved recovery checkpoint, and completed Save/Don't Save answers exit through the ordinary event loop. No readiness percentage change.
|
||||
- **2026-10-12** · Orderly native exit writes the latest recovery state after finalizing current quit approvals; incomplete or stale plans keep their documents, and Undo to the saved state clears stale recovery. Unavailable or failed recovery is reported. Cancelable macOS Dock Quit remains open (#544). No readiness percentage change.
|
||||
- **2026-10-12** · Recovered documents keep a checkpoint until saved, closed or reverted, including a second crash before autosave. Restarted document IDs and explicit recovery folders preserve other snapshots; failed republishing retains the original. No readiness percentage change.
|
||||
|
||||
@@ -1130,6 +1130,8 @@ pub fn show(app: &mut DesignApp, ctx: &egui::Context) {
|
||||
"insertTable" => crate::i18n::tr(&app.ui.language, "Create Table"),
|
||||
"textFrameOptions" => crate::i18n::tr(&app.ui.language, "Text Frame Options"),
|
||||
"documentSetup" => crate::i18n::tr(&app.ui.language, "Document Setup"),
|
||||
// On a page that doesn't start a section yet, InDesign titles it New Section.
|
||||
"numberingSection" if d.b("newSection") => crate::i18n::tr(&app.ui.language, "New Section"),
|
||||
"numberingSection" => crate::i18n::tr(&app.ui.language, "Numbering & Section Options…").trim_end_matches('…'),
|
||||
"findChange" => crate::i18n::tr(&app.ui.language, "Find/Change"),
|
||||
"paragraphStyleOptions" => crate::i18n::tr(&app.ui.language, "Paragraph Style Options"),
|
||||
@@ -4156,6 +4158,54 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn on_a_page_without_a_section_the_window_is_new_section() {
|
||||
// Chris Nielsen's "Numbering Page Sections" (4:43): page 3 selected, the Pages panel menu's
|
||||
// Numbering & Section Options opens New Section with Start Section on and 1 offered.
|
||||
let mut app = DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
|
||||
app.run("file.new", json!({"pages": 6, "facingPages": true})).unwrap();
|
||||
app.canvas_rect = Some(egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(1000.0, 800.0)));
|
||||
crate::canvas::go_to_page(&mut app, 2);
|
||||
crate::menus::activate(&mut app, "layout.section", &Value::Null);
|
||||
let d = app.ui.dialog.as_ref().unwrap();
|
||||
assert_eq!(
|
||||
(d.n("page"), d.b("newSection"), d.b("startSection"), d.b("automatic"), d.s("startNumber")),
|
||||
(Some(3.0), true, true, true, "1".into())
|
||||
);
|
||||
let ctx = dialog_context("en");
|
||||
let screen = egui::Rect::from_min_size(egui::Pos2::ZERO, egui::vec2(1178.0, 814.0));
|
||||
for _ in 0..3 {
|
||||
dialog_frame(&mut app, &ctx, screen, vec![]);
|
||||
}
|
||||
let labels = dialog_frame(&mut app, &ctx, screen, vec![]);
|
||||
visible_label(&labels, screen, "New Section");
|
||||
// Typing a number in the field chooses Start Page Numbering at; OK: page 3 is page 2.
|
||||
let field = visible_label(&labels, screen, "1");
|
||||
click_dialog(&mut app, &ctx, screen, field.center());
|
||||
dialog_frame(
|
||||
&mut app,
|
||||
&ctx,
|
||||
screen,
|
||||
vec![
|
||||
egui::Event::Key { key: egui::Key::End, physical_key: None, pressed: true, repeat: false, modifiers: egui::Modifiers::NONE },
|
||||
egui::Event::Key { key: egui::Key::Backspace, physical_key: None, pressed: true, repeat: false, modifiers: egui::Modifiers::NONE },
|
||||
egui::Event::Text("2".into()),
|
||||
],
|
||||
);
|
||||
assert!(!app.ui.dialog.as_ref().unwrap().b("automatic"), "typing chose Start Page Numbering at");
|
||||
let labels = dialog_frame(&mut app, &ctx, screen, vec![]);
|
||||
click_dialog(&mut app, &ctx, screen, visible_label(&labels, screen, "OK").center());
|
||||
assert!(app.ui.dialog.is_none());
|
||||
assert_eq!(app.session.active().unwrap().doc.page_name(2), "2");
|
||||
// Opened again on that page, it is Numbering & Section Options, showing the section.
|
||||
crate::menus::activate(&mut app, "layout.section", &Value::Null);
|
||||
let d = app.ui.dialog.as_ref().unwrap();
|
||||
assert_eq!((d.b("newSection"), d.b("startSection"), d.b("automatic"), d.s("startNumber")), (false, true, false, "2".into()));
|
||||
let labels = (0..4).map(|_| dialog_frame(&mut app, &ctx, screen, vec![])).last().unwrap();
|
||||
visible_label(&labels, screen, "Numbering & Section Options");
|
||||
assert!(!labels.iter().any(|(t, _, _)| t == "New Section"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn preferences_sidebar_scroll_keeps_selected_options_visible() {
|
||||
let mut app = DesignApp::new(designcraft_engine::Session::new(), crate::Services::default());
|
||||
|
||||
@@ -55,6 +55,7 @@ const TABLE: &[(&str, [&str; 5])] = &[
|
||||
("Cut", ["Ausschneiden", "Couper", "Cortar", "カット", "剪切"]),
|
||||
("Copy", ["Kopieren", "Copier", "Copiar", "コピー", "复制"]),
|
||||
("Paste", ["Einfügen", "Coller", "Pegar", "ペースト", "粘贴"]),
|
||||
("New Section", ["Neuer Abschnitt", "Nouvelle section", "Nueva sección", "新規セクション", "新建章节"]),
|
||||
("Reverse Path", ["Pfadrichtung umkehren", "Inverser le tracé", "Invertir trazado", "パスの方向反転", "反转路径"]),
|
||||
("Set Anchor", ["Ankerpunkt festlegen", "Définir le point d’ancrage", "Definir punto de ancla", "アンカーポイントを設定", "设置锚点"]),
|
||||
("Clear", ["Löschen", "Effacer", "Borrar", "消去", "清除"]),
|
||||
|
||||
@@ -30,6 +30,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
("Cut", "قص"),
|
||||
("Copy", "نسخ"),
|
||||
("Paste", "لصق"),
|
||||
("New Section", "قسم جديد"),
|
||||
("Reverse Path", "عكس المسار"),
|
||||
("Set Anchor", "تعيين نقطة الارتساء"),
|
||||
("Clear", "مسح"),
|
||||
|
||||
@@ -28,6 +28,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
("Cut", "Taglia"),
|
||||
("Copy", "Copia"),
|
||||
("Paste", "Incolla"),
|
||||
("New Section", "Nuova sezione"),
|
||||
("Reverse Path", "Inverti tracciato"),
|
||||
("Set Anchor", "Imposta ancoraggio"),
|
||||
("Clear", "Cancella"),
|
||||
|
||||
@@ -30,6 +30,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
("Cut", "カット"),
|
||||
("Copy", "コピー"),
|
||||
("Paste", "ペースト"),
|
||||
("New Section", "新規セクション"),
|
||||
("Reverse Path", "パスの方向反転"),
|
||||
("Set Anchor", "アンカーポイントを設定"),
|
||||
("Clear", "消去"),
|
||||
|
||||
@@ -31,6 +31,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
("Cut", "Recortar"),
|
||||
("Copy", "Copiar"),
|
||||
("Paste", "Colar"),
|
||||
("New Section", "Nova seção"),
|
||||
("Reverse Path", "Inverter demarcador"),
|
||||
("Set Anchor", "Definir ponto de ancoragem"),
|
||||
("Clear", "Limpar"),
|
||||
|
||||
@@ -31,6 +31,7 @@ pub(super) const TABLE: &[(&str, &str)] = &[
|
||||
("Cut", "Вирізати"),
|
||||
("Copy", "Копіювати"),
|
||||
("Paste", "Вставити"),
|
||||
("New Section", "Новий розділ"),
|
||||
("Reverse Path", "Розвернути контур"),
|
||||
("Set Anchor", "Задати прив’язку"),
|
||||
("Clear", "Очистити"),
|
||||
|
||||
@@ -36,13 +36,17 @@ pub(crate) fn open(app: &mut DesignApp) {
|
||||
let doc = &st.doc;
|
||||
let page = current.min(doc.page_count().saturating_sub(1));
|
||||
let own = doc.sections.iter().find(|s| s.start == page);
|
||||
// A new section starts from the one the page is in.
|
||||
// A new section starts from the one the page is in. As in InDesign, the window opened on a
|
||||
// page that doesn't start a section is New Section: Start Section checked, Start Page
|
||||
// Numbering at offering 1, Automatic Page Numbering chosen.
|
||||
let base = own.or_else(|| doc.section_of(page));
|
||||
let new = page != 0 && own.is_none();
|
||||
let fields = json!({
|
||||
"page": page + 1,
|
||||
"startSection": page == 0 || own.is_some(),
|
||||
"newSection": new,
|
||||
"startSection": true,
|
||||
"automatic": own.is_none_or(|s| s.start_number.is_none()),
|
||||
"startNumber": doc.page_number(page).to_string(),
|
||||
"startNumber": if new { "1".to_string() } else { doc.page_number(page).to_string() },
|
||||
"prefix": base.map(|s| s.prefix.clone()).unwrap_or_default(),
|
||||
"style": base.map(|s| s.style).unwrap_or_default(),
|
||||
"marker": base.map(|s| s.marker.clone()).unwrap_or_default(),
|
||||
@@ -160,7 +164,12 @@ pub(crate) fn body(app: &DesignApp, ui: &mut Ui, d: &mut Dialog) {
|
||||
if ui.radio(!automatic, crate::rtl::widget(ui, tr("Start Page Numbering at:"))).clicked() {
|
||||
d.fields.insert("automatic".into(), json!(false));
|
||||
}
|
||||
ui.add_enabled_ui(!automatic, |ui| text(ui, d, "startNumber", FIELD_W));
|
||||
// As in InDesign, the number stays editable; typing one chooses Start Page Numbering at.
|
||||
let mut n = d.s("startNumber");
|
||||
if ui.add(egui::TextEdit::singleline(&mut n).desired_width(FIELD_W)).changed() {
|
||||
d.fields.insert("startNumber".into(), Value::String(n));
|
||||
d.fields.insert("automatic".into(), json!(false));
|
||||
}
|
||||
});
|
||||
ui.add_space(4.0);
|
||||
group(ui, rtl, tr("Page Numbering"), |ui| {
|
||||
@@ -200,7 +209,12 @@ pub(crate) fn body(app: &DesignApp, ui: &mut Ui, d: &mut Dialog) {
|
||||
}
|
||||
});
|
||||
if value == ChapterSource::UserDefined {
|
||||
ui.add_enabled_ui(source == value, |ui| text(ui, d, "chapterStart", FIELD_W));
|
||||
// Editable whichever is chosen, as in InDesign; typing a number chooses it.
|
||||
let mut n = d.s("chapterStart");
|
||||
if ui.add(egui::TextEdit::singleline(&mut n).desired_width(FIELD_W)).changed() {
|
||||
d.fields.insert("chapterStart".into(), Value::String(n));
|
||||
d.fields.insert("chapterSource".into(), json!(value));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user