M7/M14: comment balloons in the margin; ROADMAP alpha and parity estimates; README Review and Layout screenshots; cargo xtask alias

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon ThomasandClaude Opus 5.5 committed 2026-10-06 01:38:55 -04:00
1 parent f38710fcb6
commit 6e9dc4bab4
7 files changed
+178 -44

No files matched your search

+2
View File
@@ -0,0 +1,2 @@
[alias]
xtask = "run --package xtask --"
+1
View File
@@ -47,6 +47,7 @@ Generated-in-code art is original and has no file to list: the UI icon set (`cra
| `docs/images/design.png` | WordCraft contributors | screenshot of WordCraft itself (sample document written for WordCraft, rendered by `ui_shot`) | MIT OR Apache-2.0 | Original; no Microsoft UI or assets |
| `docs/images/dark.png` | WordCraft contributors | screenshot of WordCraft itself (sample document written for WordCraft, rendered by `ui_shot`) | MIT OR Apache-2.0 | Original; no Microsoft UI or assets |
| `docs/images/backstage.png` | WordCraft contributors | screenshot of WordCraft itself (sample document written for WordCraft, rendered by `ui_shot`) | MIT OR Apache-2.0 | Original; no Microsoft UI or assets |
| `docs/images/layout.png` | WordCraft contributors | screenshot of WordCraft itself (sample document written for WordCraft, rendered by `ui_shot`) | MIT OR Apache-2.0 | Original; no Microsoft UI or assets |
| `docs/brand/LICENSE-brand.txt` | ArtCraft Team | craftrules `assets/brand/` | ArtCraft trademark, `docs/brand/LICENSE-brand.txt` | Not open source; usable unmodified only |
| `docs/brand/artcraft-logo-white.png` | ArtCraft Team | craftrules `assets/brand/` | ArtCraft trademark, `docs/brand/LICENSE-brand.txt` | Not open source; usable unmodified only |
| `docs/brand/artcraft-logo-white.svg` | ArtCraft Team | craftrules `assets/brand/` | ArtCraft trademark, `docs/brand/LICENSE-brand.txt` | Not open source; usable unmodified only |
+13 -9
View File
@@ -68,7 +68,7 @@ Every screenshot below is WordCraft itself, rendered offscreen by its own UI tes
<table>
<tr>
<td width="50%" valign="top"><img src="docs/images/review.png" alt="The Review tab with Track Changes on: the inserted words Cheaper rent is one reason and forty are underlined in magenta, the replaced words are struck through, two commented phrases are shaded and the Comments pane on the right shows both comments with Go to, Resolve and Delete buttons" width="100%"><p align="center"><sub><b>Review.</b> Track changes, comments, accept and reject, spelling and grammar as you type.</sub></p></td>
<td width="50%" valign="top"><img src="docs/images/review.png" alt="The Review tab with Track Changes on: the word forty is inserted in magenta and thirty struck through; three commented phrases are shaded and joined by dashed leader lines to comment balloons in a grey markup area to the right of the page" width="100%"><p align="center"><sub><b>Review.</b> Track changes, comment balloons in the margin, accept and reject, spelling and grammar as you type.</sub></p></td>
<td width="50%" valign="top"><img src="docs/images/references.png" alt="The References tab with two pages side by side: a table of contents with dotted leaders and page numbers on page one, and a styled table, numbered list and hyperlink on page two" width="100%"><p align="center"><sub><b>References.</b> Tables of contents, footnotes, citations in APA, MLA, Chicago or IEEE, index and captions.</sub></p></td>
</tr>
<tr>
@@ -76,6 +76,9 @@ Every screenshot below is WordCraft itself, rendered offscreen by its own UI tes
<td width="50%" valign="top"><img src="docs/images/dark.png" alt="WordCraft in dark mode with the Insert tab open and formatting marks shown: pilcrows at paragraph ends and dots for spaces" width="100%"><p align="center"><sub><b>Dark mode</b> with formatting marks, and the Insert tab: tables, pictures, shapes, links, headers, footers, fields and symbols.</sub></p></td>
</tr>
<tr>
<td colspan="2"><img src="docs/images/layout.png" alt="The Layout tab at 80% zoom: the first paragraph opens with a three-line drop cap E, a dark blue circle sits beside the second section with its paragraph wrapping around it and hyphenating art-ist at the line end, every line is numbered in the left margin and a thin blue border surrounds the page" width="100%"><p align="center"><sub><b>Layout.</b> Drop caps, text wrapping around pictures and shapes, automatic hyphenation, line numbers and page borders.</sub></p></td>
</tr>
<tr>
<td colspan="2"><img src="docs/images/backstage.png" alt="The File tab start page with a Good morning greeting, thumbnails of the Blank document, Studio handbook, Letter, Résumé and Report templates, and a list of recent documents" width="100%"><p align="center"><sub><b>File.</b> Start from a template, open recent documents, edit properties, export to PDF and other formats.</sub></p></td>
</tr>
</table>
@@ -107,11 +110,11 @@ Every screenshot below is WordCraft itself, rendered offscreen by its own UI tes
| **Paragraphs** | Alignment, indents (draggable on the ruler), spacing, line spacing, tabs with leaders, borders, shading, keep with next, widow/orphan control |
| **Styles** | Built-in style set, live gallery, Styles pane, create/modify/update styles, style sets, themes |
| **Lists** | Bullets, numbering, multilevel, restart, set value, custom formats |
| **Tables** | Insert by grid, merge/split, styles with banded rows, borders, shading, header rows repeated across pages, sort, formulas, text ↔ table |
| **Pages** | Margins, orientation, size, columns, page/column/section breaks, headers and footers (first page, odd/even), page numbers, watermark |
| **Objects** | Pictures (resize, crop, recolour, brightness/contrast, transparency, background removal, picture styles, rotate), shapes, text boxes, floating position |
| **Tables** | Insert by grid, merge/split, styles with banded rows, borders, shading, header rows repeated across pages, rows that split across pages, sort, formulas, text ↔ table |
| **Pages** | Margins, orientation, size, columns, page/column/section breaks, headers and footers (first page, odd/even), page numbers, watermark, page borders, line numbers, vertical alignment, drop caps, automatic hyphenation |
| **Objects** | Pictures (resize, crop, recolour, brightness/contrast, transparency, background removal, picture styles, rotate), shapes, text boxes, floating position with text wrapping (square, top and bottom, behind or in front of text) |
| **References** | Table of contents, footnotes and endnotes, citations and bibliography (APA, MLA, Chicago, IEEE), captions, table of figures, cross-references, index, table of authorities |
| **Review** | Spelling and grammar with suggestions, thesaurus, word count, comments, track changes, accept/reject, compare documents, restrict editing, accessibility checker, document inspector |
| **Review** | Spelling and grammar with suggestions, thesaurus, word count, comments in margin balloons or a pane, track changes, accept/reject, compare documents, restrict editing, accessibility checker, document inspector |
| **Mailings** | Mail merge from CSV, merge fields, address block, greeting line, rules, preview, finish to a document; envelopes and labels |
| **View** | Print layout, web layout, draft, read mode, focus, zoom, one/multiple pages, page width, Navigation pane, rulers, gridlines, dark mode |
| **Files** | .docx read/write (opens in Word), PDF export, .odt, .rtf, .html, .md, .txt import/export, page images |
@@ -174,10 +177,11 @@ check and the wasm build. Contributor and agent instructions: [AGENTS.md](AGENTS
## Roadmap
WordCraft covers 87% of Word's ribbon features with commands today; we estimate about 58% of
real feature parity once depth is counted. Next: text wrap around floating pictures, margin
comment balloons, column balancing, charts, an equation editor and signed releases for every
platform. Details and estimates: [ROADMAP.md](ROADMAP.md).
WordCraft covers 87% of Word's ribbon features with commands today; counting depth and
fidelity, we estimate about 62% of real feature parity. An alpha for everyday writing is close:
the remaining work is mostly testing against real-world .docx files, native printing and the
first signed builds. Charts, SmartArt, the equation editor and the Draw tab come after.
Details and estimates: [ROADMAP.md](ROADMAP.md).
## The Crafting Apps
+66 -32
View File
@@ -10,13 +10,40 @@ and agent control. This file tracks where we are honestly. Generated numbers com
|---|---|
| Commands (every action, scriptable by CLI/MCP/control channel) | **389** |
| Feature catalog coverage (Word ribbon/menu features with a command) | **354 / 405 (87%)** |
| **Estimated real feature parity** (depth and fidelity, not just a command) | **~58%** |
| Tests | ~240 (unit, round-trip, fuzz/proptest, MCP acceptance) |
| **Estimated real feature parity** (depth and fidelity, not just a command) | **~62%** |
| **Distance to alpha** | **~85% of the way; ≈20–25 h of Claude wall-clock work** |
| **Distance to 100% parity** | **≈120–150 h of Claude Opus 5.5 wall-clock work** (with parallel agents) |
| Tests | ~225 test functions (unit, round-trip, fuzz/proptest, MCP acceptance) |
| Layout speed (188-page document) | 61 ms cold, **1.4 ms** relayout after an edit |
| Code | ~42k lines of Rust in 15 crates |
| Code | ~44k lines of Rust in 12 crates and 3 apps |
Catalog coverage overstates parity: many commands are first versions. The estimate weighs each
area by how much of Word's behaviour it reproduces.
Catalog coverage overstates parity: many commands are first versions. The real-parity estimate
weighs each area by how much of Word's behaviour it reproduces, and by how often people use it.
## Alpha
**What we mean by alpha:** someone can write, format and review real documents every day, open
the .docx files they receive and send back files Word opens cleanly, on every desktop platform
from a signed download, without losing work.
| Alpha requirement | State |
|---|---|
| Editing, formatting, styles, lists, tables, headers/footers, references, review | done (first versions, tested) |
| Pagination fidelity: wrap, row splitting, hyphenation, drop caps, line numbers, borders | done this arc |
| Comments in margin balloons, track changes | done |
| Never-crash standard (no panics, hostile-param fuzzing, panic guard) | done |
| Autosave and crash recovery | done; needs a soak test |
| **DOCX fidelity against a corpus of real-world files** (open, render, round-trip, fix) | **not started — the main alpha blocker (≈10 h)** |
| Footnotes that continue onto the next page; column balancing | missing (≈4 h) |
| Native printing (today printing goes through PDF) | missing (≈4 h) |
| Signed builds for macOS, Windows, Linux, FreeBSD and web | pipeline written; **needs the GitHub remote and release secrets from the owner** |
| Real app icon / mascot art | placeholder; **needs owner art** |
So: alpha is roughly **85% of the way**, with about **20–25 hours** of agent work left, plus two
owner actions (push to `github.com/storytold/wordcraft` and enable the release secrets, and supply
the icon art).
## Parity by area
| Area | Status | Parity |
|---|---|---|
@@ -24,16 +51,16 @@ area by how much of Word's behaviour it reproduces.
| Character & paragraph formatting | Nearly all properties; Font/Paragraph dialogs | 85% |
| Styles (gallery, pane, create/modify, style sets, themes) | Good | 75% |
| Lists (bullets, numbering, multilevel, restart, set value) | Good | 75% |
| Tables (insert, merge/split, styles, borders, header rows, sort, formula) | Good; no row splitting across pages, no drawn tables | 65% |
| Page layout (margins, size, orientation, columns, breaks, sections) | Good; columns don't balance, line numbers/page borders/vertical alignment not drawn | 60% |
| Tables (insert, merge/split, styles, borders, header rows, sort, formula) | Good; rows split across pages; no drawn tables, no nested-table polish | 72% |
| Page layout (margins, size, orientation, columns, breaks, sections) | Good; page borders, line numbers, vertical alignment, drop caps, hyphenation; columns don't balance | 72% |
| Headers/footers, page numbers, fields | Good; first/even/odd, link to previous | 70% |
| Footnotes/endnotes | Placed and editable; long notes don't continue onto the next page | 60% |
| References (TOC, citations APA/MLA/Chicago/IEEE, bibliography, index, figures, cross-refs, TOA) | Working first versions | 60% |
| Review (spelling, grammar, thesaurus, comments, track changes, compare, protect) | Good; comments show in a pane, not margin balloons | 65% |
| Review (spelling, grammar, thesaurus, comments, track changes, compare, protect) | Good; comment balloons in the margin; no track-changes balloons | 75% |
| Mailings (mail merge, rules, preview, envelopes, labels) | Working | 70% |
| Pictures & shapes (insert, size, crop, recolour, effects, styles, float position) | Text does not yet wrap around floating objects; text boxes don't render their text | 40% |
| Pictures & shapes (insert, size, crop, recolour, effects, styles, float position) | Text wraps around floats (rectangular); text boxes render their text; no tight/contour wrap, no rotation handles | 55% |
| Draw tab (ink), SmartArt, charts, 3D models, equations editor | Not started / linear equations only | 5% |
| File formats: DOCX read/write | Good (Word opens our files); charts/SmartArt/OLE dropped | 75% |
| File formats: DOCX read/write | Good (Word opens our files); charts/SmartArt/OLE dropped; untested on a real-world corpus | 75% |
| File formats: PDF, ODT, RTF, HTML, Markdown, TXT | Working | 70% |
| View modes (print, web, draft, read, focus, zoom, navigation pane) | Working | 70% |
| Backstage (new from templates, open, info, export, options) | Working; printing goes through PDF | 55% |
@@ -41,40 +68,47 @@ area by how much of Word's behaviour it reproduces.
## Estimate to 100%
**About 140–180 hours of Claude Opus 5.5 wall-clock work** (with parallel agents), in this order:
**About 120–150 hours of Claude Opus 5.5 wall-clock work** (with parallel agents), in this order:
1. **Text wrap around floating objects, text box rendering, drop caps** (≈15 h) — biggest visual gap.
2. **Layout fidelity**: row splitting across pages, column balancing, line numbers, page borders,
vertical alignment, footnote continuation, auto-hyphenation, kerning/ligature options (≈25 h).
3. **Comments in margin balloons, track-changes balloons, formatting revisions** (≈12 h).
4. **Draw tab / ink, shapes on a canvas, grouping, rotation, z-order** (≈20 h).
5. **Charts (own renderer) and SmartArt-style diagrams** (≈20 h).
6. **Equation editor (OMML read/write, 2D layout)** (≈15 h).
7. **Dialog depth**: every Word dialog with all its options (Font, Paragraph, Tabs, Borders and
1. **Alpha blockers** (≈20–25 h): DOCX fidelity corpus, footnote continuation, column balancing,
native printing, autosave soak test, first signed release.
2. **Objects** (≈15 h): tight/through (contour) wrap, rotation and resize handles on the canvas,
grouping, z-order polish, track-changes balloons and formatting revisions.
3. **Draw tab / ink** (≈15 h).
4. **Charts (own renderer) and SmartArt-style diagrams** (≈20 h).
5. **Equation editor (OMML read/write, 2D layout)** (≈15 h).
6. **Dialog depth**: every Word dialog with all its options (Font, Paragraph, Tabs, Borders and
Shading, Page Setup, Styles, Columns, Index/TOC options, Mail Merge wizard, Options panes) (≈20 h).
8. **DOCX fidelity corpus**: round-trip and render a public corpus against Word, fix differences (≈20 h).
9. **Native printing, accessibility (screen readers), localisation, RTL/complex scripts** (≈15 h).
10. **Packaging and signed releases for every platform** (≈5 h, pipeline copied from PhotoCraft).
7. **Accessibility (screen readers), localisation, RTL and complex scripts** (≈15 h).
8. **Long tail**: kerning/ligature options, drawn tables, nested-table polish, more templates,
Word's less-used commands still missing from the catalog (≈10 h).
## Milestones
| # | Milestone | State |
|---|---|---|
| M0 | Skeleton + vertical slice (model, layout, render, engine, Word-style UI, CLI, MCP, web) | **done** |
| M1 | DOCX I/O | **done** (first version) |
| M1 | DOCX I/O | **done** (first version; corpus testing next) |
| M2 | Home tab complete | **done** |
| M3 | Insert tab | mostly done (charts/SmartArt/icons/3D missing) |
| M4 | Layout + Design tabs | mostly done (rendering gaps above) |
| M5 | Tables | mostly done |
| M6 | References | first version done |
| M7 | Review | mostly done |
| M4 | Layout + Design tabs | **done** except column balancing |
| M5 | Tables | **done** (row splitting landed) |
| M6 | References | first version done; footnote continuation missing |
| M7 | Review | **done** (margin balloons landed) |
| M8 | View | mostly done |
| M9 | Mailings | done (first version) |
| M10 | File/Backstage | mostly done |
| M11 | Draw + objects | started |
| M10 | File/Backstage | mostly done; native printing missing |
| M11 | Draw + objects | text wrap and text boxes done; ink, rotation, grouping missing |
| M12 | Formats breadth (PDF, ODT, RTF, HTML, MD, TXT) | **done** (first versions) |
| M13 | Performance budgets | on track (1.4 ms relayout) |
| M14 | 1.0 polish, packaging, signing | not started |
| M14 | 1.0 polish, packaging, signing | pipeline written; waiting on remote and secrets |
## Current focus
Floating-object text wrap and text boxes; layout fidelity items; README screenshots; release pipeline.
## Recently landed
- Text wraps around floating pictures and shapes; text boxes lay out their own text.
- Table rows split across pages between lines (Can't Split honoured, header rows repeat).
- Drop caps; automatic hyphenation with Word's 0.25" hyphenation zone; soft hyphens.
- Page borders measured from the page edge, line numbers, vertical alignment, column separators.
- Comment balloons in a markup area beside each page, with leader lines to their anchors.
## Next
The DOCX fidelity corpus, then footnote continuation, column balancing and native printing.
+96 -3
View File
@@ -11,7 +11,7 @@ use wordcraft_doc::{Pos, StoryRef};
use wordcraft_layout::{DocLayout, Page, Placed};
use crate::WordApp;
use crate::theme::{Tokens, regular};
use crate::theme::{Tokens, regular, semibold};
/// Points on screen per document point at 100% (96 px per inch, like a word processor).
pub const PX_PER_PT: f32 = 96.0 / 72.0;
@@ -71,9 +71,18 @@ pub struct Geometry {
pub scale: f32,
}
/// Width of the markup area beside each page for comment balloons (points), or 0.
pub fn markup_width(app: &WordApp) -> f32 {
let v = &app.session.view;
// Word shows comments either in balloons (contextual) or in the Comments pane (list).
let on = v.show_markup && !v.comments_pane && !v.read_mode && !v.multi_page && v.mode == wordcraft_layout::ViewMode::Print;
if on && !app.session.doc.comments.is_empty() { 216.0 } else { 0.0 }
}
pub fn geometry(app: &WordApp, l: &DocLayout, avail: egui::Vec2) -> Geometry {
let v = &app.session.view;
let maxw = l.pages.iter().map(|p| p.w).fold(0.0f32, f32::max).max(72.0);
let markup = markup_width(app);
let maxw = l.pages.iter().map(|p| p.w).fold(0.0f32, f32::max).max(72.0) + markup;
let maxh = l.pages.iter().map(|p| p.h.min(20_000.0)).fold(0.0f32, f32::max).max(72.0);
let web = v.mode != wordcraft_layout::ViewMode::Print;
let mut scale = v.zoom.clamp(0.1, 5.0) * PX_PER_PT;
@@ -99,7 +108,9 @@ pub fn geometry(app: &WordApp, l: &DocLayout, avail: egui::Vec2) -> Geometry {
let h = chunk.iter().map(|p| p.h.min(1e6) * scale).fold(0.0f32, f32::max);
let mut x = (content_w - row_w) / 2.0;
for p in chunk {
rects.push(Rect::from_min_size(pos2(x, y), vec2(p.w * scale, p.h.min(1e6) * scale)));
// Pages narrower than the widest keep their markup area beside them.
let px = x + (maxw - markup - p.w).max(0.0) * scale / 2.0;
rects.push(Rect::from_min_size(pos2(px, y), vec2(p.w * scale, p.h.min(1e6) * scale)));
x += maxw * scale + GAP;
}
y += h + GAP;
@@ -258,6 +269,7 @@ pub fn show(app: &mut WordApp, ui: &mut Ui) {
let n = layout.pages.len();
app.canvas.textures.retain(|k, _| *k < n);
app.canvas.page_rects = rects.clone();
balloons(app, ui, &painter, &rects, &layout, geo.scale);
// Selection.
if !app.session.sel.is_collapsed() {
let (a, b) = app.session.sel.ordered();
@@ -339,6 +351,87 @@ pub fn show(app: &mut WordApp, ui: &mut Ui) {
}
}
/// Comment balloons in the markup area right of each page, joined to their anchors.
fn balloons(app: &mut WordApp, ui: &mut Ui, painter: &egui::Painter, rects: &[Rect], layout: &DocLayout, scale: f32) {
let mw = markup_width(app);
if mw <= 0.0 {
return;
}
let t = Tokens::get(ui.ctx());
let clip = ui.clip_rect();
// (page, anchor x, anchor y, id) for each anchored, unresolved-or-not comment.
let mut by_page: HashMap<usize, Vec<(f32, f32, u32, Pos)>> = HashMap::new();
for (id, pos) in wordcraft_engine::cmd::review::comment_list(&app.session) {
let Some(pos) = pos else { continue };
let Some(c) = layout.caret_on(&pos, app.session.page_hint) else { continue };
by_page.entry(c.page).or_default().push((c.x, c.top + c.height, id, pos));
}
let palette = [t.blue, Color32::from_rgb(0xB0, 0x3A, 0x2E), Color32::from_rgb(0x2E, 0x7D, 0x32), Color32::from_rgb(0x8E, 0x44, 0xAD), t.orange];
let mut authors: Vec<String> = Vec::new();
let mut clicked: Option<Pos> = None;
// The markup area extends each page.
for pr in rects {
let area = Rect::from_min_max(pos2(pr.max.x, pr.min.y), pos2(pr.max.x + mw * scale, pr.max.y));
if area.intersects(clip) {
painter.rect_filled(area, 0.0, Color32::from_rgb(0xF3, 0xF3, 0xF3));
painter.line_segment([area.left_top(), area.left_bottom()], Stroke::new(1.0, Color32::from_rgb(0xE0, 0xE0, 0xE0)));
}
}
for (pi, list) in by_page.iter_mut() {
let Some(pr) = rects.get(*pi) else { continue };
if !pr.expand(400.0).intersects(clip) {
continue;
}
list.sort_by(|a, b| a.1.total_cmp(&b.1).then(a.0.total_cmp(&b.0)));
let x0 = pr.max.x + 10.0;
let w = (mw * scale - 20.0).max(60.0);
let mut next_y = pr.min.y;
for (ax, ay, id, pos) in list.iter() {
let Some(c) = app.session.doc.comments.get(id) else { continue };
let text = app.session.doc.plain_text(StoryRef::Part(c.part));
let author = if c.author.is_empty() { "Author".to_string() } else { c.author.clone() };
let ai = authors.iter().position(|a| *a == author).unwrap_or_else(|| {
authors.push(author.clone());
authors.len() - 1
});
let color = palette.get(ai % palette.len()).copied().unwrap_or(t.blue);
let fs = (11.0 * scale / PX_PER_PT).clamp(8.0, 16.0);
let head = painter.layout(author.clone(), semibold(fs), t.text, w - 16.0);
let body = painter.layout(text.trim().to_string(), regular(fs), if c.resolved { t.text_dim } else { t.text }, w - 16.0);
let h = head.size().y + body.size().y + 16.0;
let anchor = pos2(pr.min.x + ax * scale, pr.min.y + ay * scale);
let top = (anchor.y - 12.0).max(next_y);
let card = Rect::from_min_size(pos2(x0, top), vec2(w, h));
next_y = card.max.y + 6.0;
if !card.intersects(clip) {
continue;
}
let selected = app.session.sel.focus.path == pos.path && app.session.sel.focus.story == pos.story;
// Leader: from the anchor along the text to the page edge, then to the card.
let lead = Stroke::new(if selected { 1.5 } else { 1.0 }, color.linear_multiply(if selected { 1.0 } else { 0.7 }));
dashed(painter, anchor, pos2(pr.max.x, anchor.y), lead);
painter.line_segment([pos2(pr.max.x, anchor.y), pos2(x0, top + 10.0)], lead);
painter.rect_filled(card.translate(vec2(0.0, 1.0)), 4.0, t.page_shadow);
painter.rect_filled(card, 4.0, if selected { t.checked } else { Color32::WHITE });
painter.rect_stroke(card, 4.0, Stroke::new(if selected { 1.5 } else { 1.0 }, color), egui::StrokeKind::Inside);
painter.rect_filled(Rect::from_min_size(card.min, vec2(4.0, h)), egui::CornerRadius { nw: 4, sw: 4, ne: 0, se: 0 }, color);
painter.galley(pos2(card.min.x + 10.0, card.min.y + 6.0), head.clone(), t.text);
painter.galley(pos2(card.min.x + 10.0, card.min.y + 10.0 + head.size().y), body, t.text);
let r = ui.interact(card, ui.id().with(("balloon", *id)), Sense::click());
if r.hovered() {
ui.ctx().set_cursor_icon(egui::CursorIcon::PointingHand);
}
if r.clicked() {
clicked = Some(pos.clone());
}
}
}
if let Some(p) = clicked {
app.session.sel = wordcraft_engine::Selection::caret(p);
app.canvas.want_focus = true;
}
}
fn dashed(p: &egui::Painter, a: Pos2, b: Pos2, s: Stroke) {
p.extend(egui::Shape::dashed_line(&[a, b], s, 4.0, 3.0));
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 856 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 896 KiB

After

Width:  |  Height:  |  Size: 855 KiB