Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

11KB

Sprint Backlog

Sprint: 9 Dates: 2026-10-27 - 2026-10-31 Sprint Goal: Give static and dynamic text elements a real, independently adjustable width and height, so that content too long to fit wraps onto additional lines and is clipped (not silently overrun) once it exceeds the box — using Debenu's native wrap/box-drawing primitives for the real PDF and GDI+'s native rectangle-wrap for a close design-time approximation on the canvas and preview panel, directly answering the human product owner's “make the boxes longer” request.

Committed Items

Story Size Status Tasks
Add an adjustable width and height with text wrapping to static and dynamic text elements 13 points Done - [x] Add Width/Height properties to TextElementLayout (Desktop.Core) and TemplateElement (CLI), both optional/nullable so a template saved before this story (no attributes) keeps today's unbounded behavior exactly
- [x] Persist the new width/height attributes on <text> in TemplateLayoutXmlSerializer and TemplateXmlParser, following the same “optional, default preserves old behavior” convention as angle/collapsible; round-trip tests on both sides
- [x] Empirically confirm Debenu's DPLDrawWrappedText/DPLDrawTextBox semantics against the real vendor DLL (alignment flag meaning, whether DrawTextBox clips to height on its own or only wraps to width) before committing to which entry point DebenuPdfRenderer.AddPage calls when a draw's width/height is set
- [x] Add optional Width/Height to TextDraw and branch DebenuPdfRenderer.AddPage: no width/height set -> today's plain DrawText call, unchanged; width/height set -> the confirmed wrap/box entry point (DrawTextBox/DrawRotatedTextBox, whose own return value directly reports lines drawn vs. GetWrappedTextLineCount's total, so clipping needs no separate detection call)
- [x] Update RenderEngine.BuildDraws to pass the resolved element's Width/Height through to TextDraw, reusing the existing shared TextResolver for the text itself (no new resolution path)
- [x] Change TemplateCanvasControl.DrawElement/MeasureElement and TemplatePreviewBuilder's standalone-element path to use GDI+'s rectangle-bounded Graphics.DrawString/MeasureString overloads when Width/Height is set, documented explicitly as a design-time approximation (not guaranteed pixel-for-point parity with the Debenu-rendered PDF, mirroring MeasureElement's existing language)
- [x] Add a draggable width/height resize handle (and/or properties-panel numeric fields, mirroring the Address Control's X/Y/Width pattern) to CanvasElementEditor/TemplateCanvasControl — implemented as the existing font-size resize handle becoming context-sensitive (box mode vs. font-scale mode, checked once at drag-start via HasBox) rather than a second, visually-competing handle, a simpler resolution to the story's own open design question than either originally-considered option
- [x] Unit tests: model/persistence round-trip (CLI and desktop), DebenuPdfRenderer real-DLL wrap/clip regression tests (including one licensed, pixel-verified clipping test), canvas rectangle-measurement tests
- [x] Live actual built-form smoke: a real CLI render of a template with a narrow, short static and a narrow, short dynamic element against the real sample CSV, confirming actual multi-line wrapped output and clipped overflow in the produced PDF; a reflection-driven harness against the real built TemplateDesignerForm (real content TextBox, real Box width/height NumericUpDown fields, real mouse-driven resize-handle drag), with a real canvas screenshot

Daily Scrum Log

Day Date Completed Planned Blocked/At risk
1 2026-10-27 Story complete (“Add an adjustable width and height with text wrapping to static and dynamic text elements”, 13 points), all 6 ACs met, bringing Sprint 9 to 13/13 points Done. Added nullable Width/Height to TextElementLayout (Desktop.Core) and TemplateElement (CLI), persisted as optional width/height attributes on <text> (both sides independently implemented, matching this project's established convention). Real vendor-DLL investigation (a standalone probe against the actual Debenu DLL, licensed via the project's own key.txt) found and confirmed native DrawWrappedText/DrawTextBox/DrawRotatedTextBox/GetWrappedTextHeight/GetWrappedTextLineCount entry points — real screenshots proved DrawWrappedText wraps a long line onto 6 measured lines, a 20pt-tall DrawTextBox clips to only the first 2 (returning 2, not an error), and DrawRotatedTextBox composes rotation and wrapping correctly in one native call (a de-risking find for the dependent “Support rotated wrapped text...” story, flagged for re-sizing at the next refinement rather than assumed away). DebenuPdfRenderer.AddPage now branches to these native calls when a draw carries a box, with zero changes to the pre-existing unrotated/rotated DrawText/DrawRotatedText paths. Canvas (TemplateCanvasControl) and preview panel (TemplatePreviewBuilder/TemplatePreviewControl) both use GDI+'s native rectangle-bounded DrawString for a documented design-time approximation, since the desktop process has no shared code path with the CLI's Debenu engine (confirmed by inspection). The resize-handle coexistence question was resolved more simply than either option the sizing note offered: the existing font-size handle became context-sensitive (CanvasElementEditor.BeginResizeDrag/ResizeDragTo branch on HasBox, captured once at drag-start), so there is only ever one handle per element, never two. Properties panel gained “Box width”/“Box height” fields (0 = no box). Tests: 23 new (7 CLI, 16 desktop, including a licensed real-DLL test proving clipping via actual rasterized pixel rows). Full suite 448/448 -> 476/476. Live verification: real CLI render (real license key, real 392-record sample CSV) of a template with a 150x80pt static box and a 180x30pt dynamic box bound to Full Name; page 1, rasterized via Debenu's own RenderPageToFile and visually inspected, shows the static text genuinely wrapped across 4 lines and “WILLIAM EDWARD ZIMMERMAN JR” genuinely clipped to “WILLIAM EDWARD” by the 30pt height — real, observed, end-to-end proof (Designer XML -> CLI -> Debenu -> PDF), not merely unit-level. Also live-verified through a reflection-driven built-form smoke against the real TemplateDesignerForm: real content typed and committed via the actual _contentInput/CommitContentFromPanel path, 140x90pt set through the real _elementWidthInput/_elementHeightInput panel fields, then the real resize handle dragged through the actual OnMouseDown/OnMouseMove/OnMouseUp pipeline — Width/Height grew to ~198x133.5pt while FontSize stayed exactly 12, confirming box mode (not font-scale mode) was genuinely active; a real canvas screenshot from this run shows the wrapped text and both handles correctly positioned at the resized box. Process note for the retrospective: the project's own key.txt (repo root, one level above code/) was located during this story after several earlier sprints’ reviews disclosed “no license key available” — those searches only checked under code/, short of where the resolver's own upward walk (and the real key) both reach; several earlier evidence-depth caveats were avoidable, not genuine environment constraints. Sprint 9 complete — move to product-owner Sprint Review. None.

Notes

  • Capacity signal: completed totals across Sprints 1-8 are 20, 19, 18, 18, 15, 18, 18, 13 — eight data points. The 18-20 range from six of those sprints is this team's proven, repeatable velocity; both 15 (Sprint 5) and 13 (Sprint 8) are documented, deliberate under-commits around one large/risky or fresh story, not capacity misses.
  • Deliberate under-commit, reasoned explicitly, not defaulted: two larger combinations were considered and rejected at planning. Pulling this story's own dependent follow-up (“Support rotated wrapped text and a live wrap/clip indicator,” 8 pts) in the same sprint would total 21 points, a new team-wide high, for a first-of-its-kind capability with two real, still-unconfirmed vendor-API unknowns — and unlike prior “pull the whole dependent pair” precedents (each ≤13-18 points), this story is independently valuable and shippable without its follow-up, so there is no “no independent value alone” pressure to pull both at once. Pulling epic 6's multi-select/align pair (10 pts) alongside this story (23 points total) was rejected for stacking two large, genuinely novel, first-of-its-kind initiatives (a new multi-item selection model, and a new element-geometry/wrap-render model) in one sprint — exactly the risk profile this team has consistently avoided, with no external pressure cited to justify reaching for an unproven new high instead. Full reasoning: backlog/backlog.md's Sprint 9 planning outcome note.
  • No smaller item found to round out capacity, the same conclusion Sprint 8 planning reached: epic 6's multi-select cannot be cleanly pulled alone without its align/distribute pair per this team's established practice for that specific pair, and “Complete the first text-only operator workflow” (epic 1, 5 pts) remains flagged as a stale label needing re-verification before ever being pulled blind.
  • Real technical risk to watch during execution, flagged at sizing (not yet resolved): the desktop app (GDI+-based canvas/preview) and the CLI (Debenu-based render) are two separate processes with no shared wrap/line-breaking code path — canvas/preview wrap is an accepted design-time approximation, not guaranteed to match the final PDF's exact wrap points. This is a documented, accepted scope boundary (mirroring MeasureElement's existing “design-time visual approximation” language), not a defect to fix in this sprint.
  • Sequencing recommendation beyond this sprint: “Support rotated wrapped text and a live wrap/clip indicator for text elements” (8 pts, epic 4) is the natural next pull once this story lands, then “Add an adjustable width and height with text wrapping to Address Control lines” (8 pts, epic 4). Epic 6's multi-select/align pair (10 pts) and undo/redo (13 pts) remain queued and unchanged, available whenever a future planning session chooses them over continuing the wrap/clip chain.
  • Impediments: template asset path strategy (absolute vs. relative) and UNC timeout/retry behavior remain open in logs/impediment_log.md. Neither blocks this sprint's committed item.
  • Carried over from previous sprint: none (Sprint 8 completed both committed stories, 13/13 points).

Execution Order

Single committed story this sprint; no dependency ordering needed.

Daily Scrum Log

Day Date Completed Planned Blocked/At risk

Powered by TurnKey Linux.