Skip to content

Deck - #103

Open
brokkoli71 wants to merge 10 commits into
masterfrom
deck
Open

Deck#103
brokkoli71 wants to merge 10 commits into
masterfrom
deck

Conversation

@brokkoli71

Copy link
Copy Markdown
Owner

No description provided.

brokkoli71 and others added 10 commits July 6, 2026 13:45
A native slide editor in its own module deck.py, lazy-imported by
sidemark.py via ☰ "New presentation", Ctrl+Alt+P, or --presentation/--deck:

- 16:9 slides (1280×720 logical) stored as plain-JSON .smdeck
- quick-start layouts: title slide, heading + text, blank
- textboxes: inline editing, drag, resize handles, size/bold/alignment
- images: clipboard paste, file drop, or picker; aspect-preserving
- alignment snapping to slide center and sibling edges with guides
- deck-owned undo/redo, delegated from the window's Ctrl+Z/Y
- vector PDF export (960×540 pt, searchable text)

Window integration mirrors text mode (_deck_mode/_deck_view/_deck_path);
deck.py installed beside sidemark.py (PKGBUILD, aur, install.sh); bash
completion, .desktop keywords, README section, ideas.csv #96; TestDeckMode
suite (15 tests) — full suite 464 passed.

Kept on an experimental branch: Deck may later ship as an extension or
separate application rather than in the default install.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… slides, speaker notes, ink, presenter, autosave

Deck becomes a third mode of Sidemark's one window UI (pdf/text/deck)
instead of a self-contained widget. DocumentSession.doc_mode drives a
declarative _MODE_CHROME table; DeckView is now only the slide canvas
mounted in the paned's canvas_box, with all chrome supplied by the
window (deck header cluster). Sidebar thumbnails go through the new
_ThumbnailProvider interface (_PdfThumbnails/_DeckThumbnails) with
capability-gated PDF-only DnD. Speaker notes edit slide["notes"] in the
.smdeck; per-slide ink (pen/highlighter/eraser) renders in canvas,
thumbs, presenter and PDF export; textboxes render inline math/Markdown.
DeckPresenterWindow (F5) and deck autosave/recovery added.

TestDeckMode grown to 23; full suite 472 passing. See ideas.csv row 97.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
First-session guide to the project: what Sidemark is, the one-minute
architecture (canvas/notes/text/deck modes, DocumentSession proxying,
thumbnail provider interface), testing via run_tests.sh (headless
Weston), the feature acceptance checklist, and conventions/gotchas.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tes)

Opening a .pptx now imports an editable Sidemark Deck instead of a flat
PDF. _convert_pptx_then_open runs LibreOffice pptx→pdf, _rasterize_pdf_slides
renders each page to a PNG (PyMuPDF, PPTX_IMPORT_WIDTH), and the new
deck.deck_from_images builds a deck where each slide is one full-bleed
picture (fit into 16:9, non-16:9 letterboxed) carrying its speaker notes
from _extract_pptx_notes. _open_deck_model (factored out of _open_deck)
mounts the in-memory deck untitled+dirty so the first save names the
.smdeck. From there: reorder, ink/textbox annotation, F5 presenter,
PDF export.

The slides are pictures — original text isn't editable as text; that's a
deliberate MVP (ideas.csv row 98), with structured text (row 99) and
theme import so new slides match (Phase 2) as follow-ups. Removes the old
pptx→PDF path and _apply_pptx_notes; cleans up the temp dir.

TestPptxNotes covers deck_from_images fit/notes/empty, _rasterize_pdf_slides
and _open_imported_deck. Full suite 474. Docs: README, CLAUDE.md, ideas.csv
rows 98-100.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LibreOffice writes a tagged (accessibility) structure tree that MuPDF
dislikes, so rasterizing each page of the converted PDF printed a harmless
"No common ancestor in structure tree" to stderr per slide, flooding the
terminal on import. The pixmaps are correct, so mute MuPDF's stderr display
(fitz.TOOLS.mupdf_display_errors) around the rasterize loop and restore the
prior setting afterward.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…button

Presenting a deck now shows the next slide as a preview on the operator's
canvas, matching the PDF presenter's PowerPoint-style stack look (it was
deferred for decks in v2). DeckView gains set_stack_preview / _stack_layout
/ _draw_stack_peek: while presenting, the current slide shrinks and the next
slide is drawn smaller and dimmed below it (or beside it on a wide/short
canvas — whichever keeps the current slide larger, since slides are 16:9).
Space is reserved even on the last slide so the slide size never jumps.
Wired from _show_present_bar in deck mode.

Also fixes a bug this surfaced: launching straight into deck mode
(--presentation) showed no presenter button in the top-right corner. The
wide deck bar lives in the scrollable start cluster but _calibrate_header
measured its full width into every collapse breakpoint, forcing max collapse
(level 3), which hides presenter/search/share. Calibration now measures with
the deck bar hidden, so it scrolls instead of forcing collapse.

Tests: next-slide preview (shrink + stable last slide), stack below/beside
layout math, and a regression test that the deck bar can't hide the present
button. README + ideas.csv row 101. Full suite 477.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refresh CLAUDE.md "Current state" for the next session: PPTX import and the
deck presenter next-slide preview + present-button fix are done and pushed;
Phase 2 (deck themes + PowerPoint theme import) is the next step, and it also
builds the OOXML placeholder-chain machinery structured text import needs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Phase 2 of the deck roadmap. A deck now carries a *theme* (background,
fonts, text colors, accent, and named-layout placeholder geometry) instead
of being hardcoded Sans-on-white, and importing a .pptx synthesizes a theme
from the file so slides added to an imported deck match the original design.

Native themes (deck.py):
- DeckModel.theme, serialized in the .smdeck; FORMAT_VERSION 1→2 with
  back-compat load (_normalize_theme: v1 files → DEFAULT_THEME, v1 textboxes
  get role='body' backfilled).
- Textboxes carry a semantic role (title|subtitle|body); the old LAYOUTS
  lambdas became _BASE_LAYOUTS placeholder geometry; new_slide(layout, theme)
  materializes it. render_slide(cr, slide, theme, …) reads bg/fonts/colors,
  threaded through every caller (canvas, stack-peek, presenter, export,
  thumbnails). Inline text editor CSS now matches the theme (WYSIWYG).
- Two built-in themes in deck.THEMES: Classic (default) and Midnight.
- No colour-editing UI: a theme-picker dropdown in _build_deck_bar (labelled
  with the active theme, populated lazily) calls DeckView.set_theme (undoable).

PowerPoint theme import:
- sidemark._extract_pptx_theme parses the first slide master + theme part
  into a unit-free 'design' dict (colors resolved through <p:clrMap>, fonts
  from fontScheme, title/body geometry EMU→fraction), reusing the
  _extract_pptx_notes zip/rels walk; best-effort → None on any problem.
- deck.build_imported_theme assembles it into a theme with per-field
  fallbacks, a contrast guard, and geometry over the content layout.
- Wired through _convert_pptx_then_open → _open_imported_deck →
  deck_from_images(images, theme).

Tests: +14 (theme model round-trip/back-compat/undo, theme-driven render,
imported-theme assembly + contrast + geometry, pptx theme parse via a new
make_themed_pptx helper, end-to-end parse→build→model). README, ideas.csv
rows 102/103, and CLAUDE.md updated. Full suite green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JQHhGniyNw2Wz8cA37PGrA
Brings in two master features, both already correct for decks:
- open launched file as a tab in the last-used window: decks ride along,
  since .smdeck/.pptx route through open_file → _do_open_file.
- verbatim `code` spans + per-version instance id: the code-span change is
  in _notes_to_pango_markup (== deck.notes_to_markup), so slide textboxes
  render `code` verbatim too, no deck code changed.

Conflicts (ideas.csv, sidemark.py, test_pdfeditor.py) resolved keeping both
sides; master's ideas.csv rows renumbered 104–106 to avoid the deck rows.
Full suite green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Closes two of row 103's limits. _extract_pptx_theme now resolves the page
background with the real OOXML inheritance slide → layout → master (first
part with a <p:bg> wins, via a nested _bg_spec) and extracts picture
backgrounds: a blipFill resolves its r:embed through the part's rels to
ppt/media/*, is converted to PNG with fitz.Pixmap (CMYK→RGB guarded, since
cairo only reads PNG) and returned as design["bg_image"] (PNG bytes); a
gradient is approximated by its first stop colour.

deck.build_imported_theme base64-encodes bg_image into the theme;
render_slide paints it full-bleed (EXTEND_PAD, no seam) behind objects via
new deck._theme_bg_surface (caches under _bg_surface; to_json now cleans the
theme so the cairo surface never reaches JSON).

Tests: TestPptxNotes +4 (extract from master, layout-over-master + slide
inheritance, none when solid; make_themed_pptx gained bg_image_png/bg_on),
TestDeckMode +3 (build carries/omits bg_image, render paints it, save/load
round-trip strips the cache). README + ideas.csv (107) updated.

Note: the decks that triggered this carry no importable background (plain
bg1 master) — their look is per-slide content already preserved as the slide
picture; the real mismatch there was uninstalled source fonts. Built as the
correct general fix for decks that do have picture/layout backgrounds.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant