Add text labels: click to type on the board - #136
Merged
Merged
Conversation
FreeTextBoardObject with its rotated-rectangle geometry, archive version 7, the Label defaults, the Text tool on a new Insert tab, the label editor on the text editor layer, the font row in the property bar, and labels in the editable export overlay. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A row that stays open - Edit, and now Insert - offered its access keys to every plain letter, so typing a T into a label picked the Text tool and committed it. Text being typed answers first now, for the label editor and for the text container alike, and the label editor is given room for its border and caret so a line is never clipped while it is written. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
marcosqlbi
added a commit
that referenced
this pull request
Sep 17, 2026
…bar (#137) Pull request 3 of the 1.6.0 plan in `docs/design-objects.md`, closing #130. It adds the eight shapes, the Insert tab they come from, and the two Toolbar preferences that decide where the Insert tools live and what happens after one has been drawn. It builds on #135, which moved the per-type questions onto the records themselves — this adds a record and a geometry and touches almost none of the window's switches. ## Why it is shaped this way **A shape is taken hold of by its outline, never by its interior** (decision 11). That is the whole reason a shape can be a container: ink drawn inside one links to it and travels with it, and a tap in the middle still reaches whatever is drawn there. The band is the same eight screen pixels a frame's edge uses. **One description of the outline serves everybody.** `Core.Geometry.ShapeGeometry` returns a shape's outline as a start point and a list of line and arc steps. The surface hands the arcs straight to WPF, so a circle stays a circle at any zoom; the hit test and the area tests walk the same outline flattened to a polygon, sixty-four points to a full circle. Nothing derives the geometry a second time, which is what stops the renderer and the hit test disagreeing about where a shape's edge is — and it is what pull request 6 will read to write native PowerPoint and PDF geometry. **The area asks the outline too.** A rubber band over the empty corner of an ellipse's box does not take the ellipse; one that crosses the curve does. A box test would have been cheaper and would have felt wrong for exactly the shapes people draw around things. **Version 7 is asked for by the board that needs it.** `NeedsVersion7` is a one-line predicate the label and connector work extends; a board with only frames still writes as 6 and one with neither as 5, so a board keeps opening in the release that can read it. **The two "applies when" tests in the property bar are named statics.** `HasPrimaryColor` and `HasThickness` are each one line for the text and connector pull requests to extend, rather than a predicate repeated at every row. Applying a color, a thickness, or a fill replaces every selected stroke and shape as one step and becomes what the next shape is drawn with. **Free resize is the one thing a shape does differently.** Its corner handle takes the width and the height the pointer is at, and Shift keeps the aspect — the opposite way round from a picture, which is aspect-locked. It applies only when the selection is exactly one shape; a set still scales as a set. **The editable export keeps the shapes visible.** The overlay picture now carries the ink and the shapes, and the vector PDF path — which draws the ink itself — still gets an overlay for the shapes alone. Native shapes are pull request 6; until then nothing disappears from a deck. ## The toolbar's width Measured from the XAML for the floating palette, at the default where the Eraser is not on the bar. With the preference off both new controls are `Collapsed` and contribute nothing, so the width is the 1.5.2 width to the pixel. | Layout | Insert and Lasso on the toolbar off | on | | --- | --- | --- | | Compact (Chevron or Icons beside the size chips) | **140** | **202** | | Dual palette (the default) | **286** | **310** | The compact pair grows by the Insert button (42) and the Select chevron (20); the dual pair by 24, which is what the Insert button adds to the shared color column that sets the palette's width. Both pairs were confirmed against a running copy: the measured deltas are 62 and 24 exactly. With the Eraser on the bar — that is, with finger or mouse drawing on — the compact pair is 182 and 244. ## Decisions the plan did not settle - **The shape defaults start at the pen's defaults, not at the live pen.** Decision 5 says a shape's first outline color and thickness are "the current pen's". Reading the pen's setting at the moment a shape is drawn would make the same gesture produce different shapes depending on which color was last chosen for ink, so `ShapeSettings` instead starts at `InkPalettes.DefaultPen` (vermillion, 4) and is last-used from then on, which is what the settings table asks for. - **Proportional corners and slants.** A rounded rectangle's radius is a fifth of its short side, a parallelogram slants by a quarter of its width, a block arrow's head starts at three fifths and its shaft is half the height. Proportional rather than absolute, so a shape dragged larger keeps the look it had when it was drawn. - **The pentagon fills its box** rather than being inscribed in a circle inside it: a shape dragged out of a rectangle should occupy that rectangle. - **The Insert row is sticky**, which is what #136 settled while this was in flight: picking a tool is the start of drawing with it, and the row is where the next one comes from. This branch had it closing on a pick and took main's answer instead. - **The Select chevron is in the compact layouts only.** The plan names the Insert button for the Dual palette layout and says nothing about the chevron there; the dual palette's widths are set by a shared column and a chevron would disturb it for one setting. Lasso stays reachable from the Edit row in every layout. - **The glyphs are drawn by hand**, as the plan allows: Fluent UI System Icons has no outline shape set. Each is two nested contours filled even-odd on the same 24-unit grid, including the Insert button's. - **Alt+I opens the Insert tab.** F, E, V and H were taken. - **Ctrl+C with one shape selected still copies nothing**, as it does for a frame today. Decision 12 names a text container and a picture as the single-object cases and sends everything else through the rasterizer only when more than one thing is selected. Worth a look when the native export lands. ## Taking in the text labels (#136) `origin/main` was merged in after #136 landed, so the two sit side by side rather than in two places: - **One Insert tab and one row**: the eight shapes, a separator, then Text, which is the order the flyout shows and the order the connectors will be inserted into. - `NeedsVersion7` covers labels and shapes; the archive keeps both cases and both sets of DTO fields. - The property bar's tests now read: Color for a stroke, a shape, or a label; Thickness for a stroke or a shape; Fill for a shape; Font for a label. A color reaches strokes and shapes as one step, and labels through their own path — the one that also changes the box being typed into while a label is open. - The overlay picture carries the ink, the labels, and the shapes, and the vector path still emits one for the design objects alone. - **After inserting an object now governs the Text tool too.** It was written for the shapes, but decision 3 is about every Insert tool, so a committed label either leaves the tool for the next click or hands it back to Select. - The toolbar's Insert flyout ends with Text, and the Insert button reads as on for either tool. ## Tests Core harness: the outline of every kind at a known box; the band hitting the outline and missing both the middle and the outside, and narrowing with the zoom; an area taking a shape by its outline under both rules and refusing an empty corner of its box; a stroke touching only a shape linking to it; the archive round trip with and without a fill, the three versions, and an unknown kind normalizing to a rounded rectangle; the round trip and normalization of both Toolbar settings and the shape defaults. ## To try by hand - Draw each of the eight from the Insert tab with the pen, and with a finger under Finger drawing. Only a mouse was driven here. - Shift while dragging one out, for the square. - Tap without dragging, for the 160 x 120 shape at the tap. - Turn on **Insert and Lasso on the toolbar** and check the flyout and the Select chevron with a pen, which reaches them through the palette's own stylus path rather than through mouse promotion. - Compare the toolbar's width against 1.5.2 with the preference off, in both layouts. - Draw ink inside a shape, move the shape, and check the ink comes with it. - Set **After inserting an object** to Return to Select and draw one. - Export a board with shapes to an editable deck and to a PDF, and check they are in both. - A drag that is long in one direction and flat in the other makes a shape with almost no height. It is what was dragged and Ctrl+Z removes it, but it is worth a look before the connectors land on top of it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
marcosqlbi
added a commit
that referenced
this pull request
Sep 17, 2026
) Pull request 7 of the 1.6.0 plan in `docs/design-objects.md`: the release cut. The five features are on `main` — the grid (#134), selection by area (#135), text labels (#136), shapes and the Insert tab (#137), and connectors (#139) — and none of them touched the prose, so this is where a person is told what they got. **#138, the native editable export, must merge before this one**: the release notes and the guide both say shapes and labels leave as objects in a deck and a PDF, which is true once it lands. `VersionPrefix` goes 1.5.2 → 1.6.0, so `CHANGELOG.md` gains the matching section and the **Release notes** check applies to this pull request. `./scripts/release-notes.ps1 -Mode Verify -Version 1.6.0` passes, and `dotnet build Whiteboard.sln -c Release` is clean. ## What it affects - **`CHANGELOG.md`** — one `## 1.6.0 - 17 September 2026` section with three entries, which is the shape of 1.5.0 (3), 1.5.1 (1) and 1.5.2 (2): the Insert tab with shapes, connectors and text, selection by area, and the grid. The toolbar preference is one sentence inside the first entry rather than a fourth entry, because it is where somebody meets it. The first entry also carries the one thing a person deciding whether to upgrade has to know: a board holding any of the new objects does not open in 1.5.x. - **`README.md`** — three bullets in *Included in the application*, seven rows in *Controls*, the Preferences lists in the bullet and in the table, and the containers paragraph, which now says shapes and labels are containers and that a shape is picked up by its outline. - **`site/guide.html`** — a new *Shapes, connectors, and text* section after *Text and code*, a paragraph on area selection under *Containers*, one sentence on the grid under *Navigation*, and the Insert tab named in the command-strip section. - **`site/shortcuts.html`** — Insert, Lasso and Grid rows, the rubber band and Ctrl-to-add, and the Alt-mnemonic row extended with Alt+I, Edit L, View G, and Insert T. - **`site/index.html`** — two feature tiles, shapes/connectors/text and select by area. - **`docs/decisions.md`** — decision 31, why design objects are ordinary board objects, why a shape is taken by its outline, and why the grid is an application preference. The rest stays in `docs/design-objects.md`, whose status line is now shipped in 1.6.0. - **`TODO.md`** — the current version, which still said 1.3.0, and what 1.6.0 left out. ## Readings taken, since nobody could be asked - **`site/compare.html` is untouched.** It has no row saying Whiteboard lacks shapes, text, a grid or multi-select; the nearest, *Ink and objects*, is a statement about strokes travelling with a container and is still true. The brief said to change such cells and nothing else, so nothing else changed. - **`site/faq.html` is untouched.** No answer on it became wrong. - ***Architecture* in `README.md` is untouched.** The `Core` bullet names no types — it says "world geometry, camera math, retained board objects, commands, hit testing" — so there was no list for `ShapeGeometry`, `ConnectorGeometry` and `RotatedRectangle` to join, and the brief said to leave it alone in that case. - **Escape is an edited row, not a new one**, in both the README table and the shortcut list: Escape already had one, and a second would contradict it. - **`site/changelog.html` is untouched**, as it is generated from `CHANGELOG.md` at deployment. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #132, the fourth pull request of the 1.6.0 design objects plan
(
docs/design-objects.md).Why
A whiteboard needs a word written on it as often as it needs a drawing of one:
a heading over a sketch, a name beside an arrow, a note that has to be legible
in a recording. Until now the only text a board could hold was a pasted-code
container, with a title bar and a language, which is the wrong object for two
words over a diagram. A label is the other one: click, type, and it is on the
board with the font, size, color, style, and quarter turn you last used.
What it affects
FreeTextBoardObjectjoinsBoardObjects.csas a container:its layout rectangle, turned about its centre, is what
Boundsis the box of.Core.Geometry.RotatedRectanglecomputes that box, the four turned corners,and the inverse the hit test asks, and snaps an angle to a multiple of 45.
Core never measures text: the window measures and writes the layout size in.
CurrentVersionis 7, and a board asks for it only when itholds a label — frames alone are still 6, and neither is still 5. The check is
a one-line
NeedsVersion7that the shapes and connector pull requests extend.Everything a label is written with is optional in the file and normalized on
read: an uninstalled font becomes Segoe UI, an angle of 50° becomes 45°, and a
size outside what a label can be read at is brought back into range.
Core.Settings.LabelStyles,and
AppSettings.Labelremembering what the last label was written with. Likethe pen's color and size it is last-used rather than configured, so it has no
row in Preferences, and the settings version stays 19.
BoardSurfacein z-order with everythingelse, so they show in an export, a preview, the Explorer thumbnail, and the VS
Code preview. A selected label is outlined along its turned rectangle rather
than by the box around it; the corner handle stays on the box, which is where
the gesture looks for it, and dragging it scales the font.
the last button of its row. The shapes pull request is building the same tab in
parallel with eight buttons in front of Text; whichever merges second keeps one
tab and both sets of buttons. The optional toolbar Insert flyout and the two
Toolbar preferences belong to that pull request, and this branch does not
touch the floating toolbar at all.
sizes, B / I / U, and ↶ ↷ stepping the angle by 45°. Its "applies when" tests
are now small named statics (
HasPrimaryColor,HasThickness,IsLabel) thatthe next pull requests extend by a line each, and the existing Color row now
reaches a label's text. A pen tap on a combo box opens its list and a tap on a
button clicks it, as it already did for a toggle.
too, in the editable deck and in the vector PDF path, so nothing vanishes from
either. Native rotated text is pull request 6.
BoardPartitionernames an areaafter a label's first line when a label is the thing it is about.
Insert — offered its access keys to every plain letter, so typing a word with a
T in it while a label was open picked the Text tool and committed the label
half-written. Text being typed now answers the keyboard first, for the label
editor and for the text container alike.
Decisions the plan did not settle
AfterInsertis not wired. The preference belongs to the shapes pullrequest and is not on
mainyet, so the Text tool is sticky: it stays for thenext click, and Escape puts it down. When the two branches meet, the
coordinator has one place to hook it — the end of
CommitLabelEdit.scaled past 96 by the corner handle therefore comes back smaller than it was
saved; the layout is scaled by the same factor so the text still fills its box.
If a board should keep a 200-pixel heading instead, the clamp in
LabelStyles.ClampFontSizeis the one line to widen.PowerPoint does, so a label written at an angle grows along its own baseline.
commit: the change goes into the label and into the editor at once, and the
whole edit is still one step in the history.
of drawing with it, and the row is where the next one is picked from.
selected the first Escape deselects and the second returns to Select.
icons around it: Fluent has no plain T at this weight.
To try by hand
Driven with a pen, and with the mouse under both Mouse drawing settings:
and what you type stays where you started it as it grows.
because the tool stays. Escape cancels — a new label leaves nothing behind,
and an edited one comes back as it was. An empty label disappears.
label stays where it was, and the editor is turned with it when you reopen it.
one is being typed; then insert the next label and check it is written the
same way, including after a restart.
the text; select several labels with a rubber band and recolor them at once.
delete the label and check the ink goes too.
the label is in both, in the overlay picture.
With the mouse, in the running application, I inserted a label from the Insert
row, typed it, committed it, turned it 45°, changed its size from the property
bar, dragged it across the board, and undid all of it back to an unmodified
board. The rest of the list above — the pen, the finger, Escape, F2, several
labels at once, linked ink, the clipboard, and a saved and exported board — is
for the morning.
One to watch while you do: choosing a font or a size from the property bar
while the Text tool is still active. Automating that click left a stray empty
label behind once, which a hand could not reproduce and which leaves nothing in
the board either way, but it is worth a look.
🤖 Generated with Claude Code