mirror of
https://github.com/storytold/deckcraft.git
synced 2026-10-24 10:37:03 -06:00
Notes Page view: draw master text wrapped, as the PDF does
pdf::master_text_pieces turns the text engine's layout of the notes master's header, date, footer and page number into per-run, per-line pieces scaled to the page; the Notes Page view paints them in their sizes and colours. Stacked on #583.
This commit is contained in:
@@ -233,6 +233,54 @@ pub fn master_text_style(pres: &Presentation, m: &deckcraft_model::Master, sh: &
|
||||
TextStyle { family, size: r.size.unwrap_or(12.0).clamp(1.0, 400.0), bold: r.bold == Some(true), italic: r.italic == Some(true), color }
|
||||
}
|
||||
|
||||
/// One laid-out piece of master text on a page of `paper` points: a run's text on one line, its
|
||||
/// baseline start and its size, colour, weight and slant.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct TextPiece {
|
||||
pub at: (f64, f64),
|
||||
pub text: String,
|
||||
pub size: f64,
|
||||
pub color: deckcraft_model::Rgba,
|
||||
pub bold: bool,
|
||||
pub italic: bool,
|
||||
}
|
||||
|
||||
/// The header, date, footer and page number of `m` for page `n`, laid out by the text engine
|
||||
/// (wrapped, mixed formatting) and scaled to `paper`, for drawing without glyph access (the
|
||||
/// Notes Page view).
|
||||
pub fn master_text_pieces(pres: &Presentation, m: &deckcraft_model::Master, paper: (f64, f64), n: usize) -> Vec<TextPiece> {
|
||||
let (kx, ky) = (paper.0 / pres.notes_size.width.max(1.0), paper.1 / pres.notes_size.height.max(1.0));
|
||||
let mut out = vec![];
|
||||
for pt in deckcraft_render::place_master_texts(pres, m, n) {
|
||||
for run in &pt.layout.runs {
|
||||
let Some(g) = run.glyphs.first() else { continue };
|
||||
let text: String = pt
|
||||
.body
|
||||
.paragraphs
|
||||
.get(run.para)
|
||||
.map(|p| p.runs.iter().map(|r| r.text.as_str()).collect::<String>())
|
||||
.unwrap_or_default()
|
||||
.chars()
|
||||
.skip(run.chars.0)
|
||||
.take(run.chars.1.saturating_sub(run.chars.0))
|
||||
.collect();
|
||||
if text.trim().is_empty() {
|
||||
continue;
|
||||
}
|
||||
let p = pt.transform * kurbo::Point::new(g.1, g.2);
|
||||
out.push(TextPiece {
|
||||
at: (p.x * kx, p.y * ky),
|
||||
text,
|
||||
size: run.size * ky,
|
||||
color: run.color,
|
||||
bold: run.fake_bold || run.face.weight >= 600.0,
|
||||
italic: run.fake_italic || run.face.italic,
|
||||
});
|
||||
}
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
/// The header, date, footer and page-number text a master puts on page `n`, with where it goes,
|
||||
/// whether it's right-aligned and its style. Placeholders with no text are left out; the page
|
||||
/// number is always `n`.
|
||||
|
||||
@@ -176,6 +176,14 @@ fn master_text_wraps_and_keeps_mixed_formatting() {
|
||||
assert!(h.runs.iter().any(|r| r.color == Rgba::rgb(200, 0, 0)));
|
||||
let num: String = placed[1].body.text();
|
||||
assert_eq!(num, "4");
|
||||
// The same layout as pieces for the Notes Page view: on more than one line, scaled to paper.
|
||||
let pieces = master_text_pieces(&p, &m, (306.0, 396.0), 4);
|
||||
let mut ys: Vec<i64> = pieces.iter().map(|x| x.at.1.round() as i64).collect();
|
||||
ys.dedup();
|
||||
assert!(ys.len() >= 3, "two header lines and the number: {pieces:?}");
|
||||
assert!(pieces.iter().any(|x| x.bold && (x.size - 9.0).abs() < 0.5), "18 pt bold at half size");
|
||||
assert!(pieces.iter().any(|x| x.color == Rgba::rgb(200, 0, 0) && !x.bold));
|
||||
assert!(pieces.iter().any(|x| x.text == "4"));
|
||||
p.notes_master = Some(Arc::new(m));
|
||||
assert!(export(&p, &PdfOptions { layout: PageLayout::Notes, ..Default::default() }).unwrap().starts_with(b"%PDF"));
|
||||
}
|
||||
|
||||
@@ -132,11 +132,12 @@ pub fn notes_page(app: &mut SlideApp, ui: &mut Ui) {
|
||||
let srect = to_screen((slide_box.x0, slide_box.y0, slide_box.x1, slide_box.y1));
|
||||
let sw = srect.width();
|
||||
if let Some(m) = doc.notes_master.as_deref() {
|
||||
for (r, text, right, st) in deckcraft_engine::pdf::master_texts(&doc, m, paper, idx + 1) {
|
||||
let r = to_screen((r.x0, r.y0, r.x1, r.y1));
|
||||
let (at, align) = if right { (r.right_center(), egui::Align2::RIGHT_CENTER) } else { (r.left_center(), egui::Align2::LEFT_CENTER) };
|
||||
let c = Color32::from_rgba_unmultiplied(st.color.r, st.color.g, st.color.b, st.color.a);
|
||||
ui.painter().text(at, align, text.lines().next().unwrap_or(""), theme::font((st.size as f32 * k).max(6.0)), c);
|
||||
// Laid out by the text engine as on the PDF page: wrapped, each run in its size and colour.
|
||||
for piece in deckcraft_engine::pdf::master_text_pieces(&doc, m, paper, idx + 1) {
|
||||
let size = (piece.size as f32 * k).max(4.0);
|
||||
let at = page.min + vec2(piece.at.0 as f32 * k, piece.at.1 as f32 * k - size * 0.8);
|
||||
let c = Color32::from_rgba_unmultiplied(piece.color.r, piece.color.g, piece.color.b, piece.color.a);
|
||||
ui.painter().text(at, egui::Align2::LEFT_TOP, &piece.text, theme::font(size), c);
|
||||
}
|
||||
}
|
||||
let ppp = ui.ctx().pixels_per_point();
|
||||
|
||||
+4
-3
@@ -166,9 +166,9 @@ Detail in [animation-parity.md](animation-parity.md). 10–16 h; the pane is a *
|
||||
PDF) place the slide and notes where the notes master does and print its header, date, footer
|
||||
and page number in their own fonts, sizes and colours; PDF handouts print the handout master's.
|
||||
Notes Master view previews the slide in its slide-image placeholder. PDF pages lay master text
|
||||
out with the text engine (wrapping, mixed formatting). Left: the on-screen Notes Page view still
|
||||
draws it as one line per placeholder.
|
||||
- **Estimate:** 0.5 h.
|
||||
out with the text engine (wrapping, mixed formatting), and the Notes Page view draws the same
|
||||
layout. Left: the view draws it in the interface font (sizes, colours and weights kept).
|
||||
- **Estimate:** done for beta.
|
||||
|
||||
### Edit points, text warp, 3-D
|
||||
- **Evidence:** checklist rows "Edit points" (P1 missing), "Text warp transforms" (partial: all 40
|
||||
@@ -262,6 +262,7 @@ Detail in [localization-parity.md](localization-parity.md).
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-14 | trivial | Notes Page view draws master text wrapped, as the PDF does |
|
||||
| 2026-10-14 | trivial | PDF master header/footer text wraps and keeps mixed formatting |
|
||||
| 2026-10-14 | trivial | Notes Master slide preview; master header/footer text keeps its formatting |
|
||||
| 2026-10-14 | minor | Notes pages and PDF handouts follow the notes and handout masters |
|
||||
|
||||
Reference in New Issue
Block a user