Fix text truncation, hover-scroll, and layout overlap across the app - #71
Conversation
Converts static FitText truncation to Marquee hover-scroll across Photos, Notes, Timers, Dailies, Activity, Fishing, Market, Clock, Aethergram, Velvet, Health, and Yellow Pages, and fixes the HUD layout in Tetris, Watersort, and Breakout so Score/Level/Best pills no longer overlap the Hold/Next preview slots or each other. Most of the individual bugs traced back to a handful of repeating root causes: shared hover state feeding two stacked Marquee texts at once, one side of a row being unclamped while its sibling was, and Typography.DrawCentered's window-relative auto-wrap heuristic misfiring on small host windows (minimized-phone icon) and edge-of-row elements. Fixed each occurrence and, where the pattern was structural (GameHud pill sizing, HoverTooltip's wrap bounds), fixed the shared component instead of patching every call site by hand. Full breakdown and rationale in the PR description.
XeldarAlz
left a comment
There was a problem hiding this comment.
Verified on 39e06bc in a throwaway worktree: dotnet build clean (0 errors, 4 pre-existing NU1902 warnings), dotnet test 139/139 passing. Not run in-game here, so the screenshot iteration is taken on trust.
Approach is right: fixing GameHud.PillWidth, HoverTooltip and AppHeader.DrawTitleWithReserve at the component level instead of patching every call site is the correct call. Five inline notes, one blocking.
- WidgetChrome: MeasureTrackedWidth added trailing tracking that EyebrowWidth omits, causing the marquee threshold to disagree with the layout width callers pass as maxWidth. - YellowPagesApp.Detail: restore the accent stroke on tag pills that the old inline pill draw included. - YellowPagesApp.Browse: cache the per-label word split used by FitLabelStyle instead of re-splitting every frame per intent tile. - HoverTooltip: cap wrap width so long labels don't stretch across the full viewport. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
XeldarAlz
left a comment
There was a problem hiding this comment.
Reviewed all 41 files. Verified: built ed685cc5 clean in a detached worktree (0 errors, only the pre-existing AngleSharp NU1902 warnings).
The three root causes in the description hold up, and the fixes are the right shape: per-line hover instead of one shared boolean, both sides of a row given a floor, and the Typography.DrawCentered auto-wrap path bypassed at the call site rather than patched globally. Checked and happy with: the GameHud sizeScale plumbing (measure and draw both land on the same FontService.NearestSize bucket, so PillWidth tracks the rendered text), the HoverTooltip viewport switch, the Market hero card reflow, and the Linkshell timestamp reserve.
2 blocking (both in WidgetChrome.cs, both small), 6 non-blocking. Details inline.
One housekeeping note: ed685cc5 carries a Co-Authored-By: Claude Sonnet 5 trailer. I keep those out of this repo's history, so please drop it before merge (or I'll strip it on squash).
- WidgetChrome.EyebrowMarquee now measures fullWidth with EyebrowWidth instead of a second, disagreeing per-glyph formula, so labels that fit stop taking the clip/marquee path on hover. Deletes the dead MeasureTrackedWidth and its per-char allocation. - Brace the single-line if per repo style. - Marquee's three *Auto helpers now hover-test through UiInteract.Hover instead of raw ImGui.IsMouseHoveringRect, so gating (InputBlocked, MouseOverOverlay) applies at every *Auto call site instead of only where callers remembered to gate manually. - Extract AppSkin.HeaderActionWidth so PhotosApp's nav bar reserve can't drift from the button's actual geometry. - Recent Play chips now show a title-only line at Caption1 below M instead of dropping all text, so XS/S chips aren't unlabelled art. - Breakout's life-pip loop reads BreakoutBoard.StartingLives instead of a duplicated literal. - Velvet profile name marquee measures the untruncated display name for its box width instead of the already-ellipsised string. - Move YellowPages' IntentLabelWords cache field up with the type's other statics.
* fix(jobs): reserve header space and marquee row text Jobs was the one app left off PR #71's sweep: its header title used plain Typography.DrawCentered (no reserve for the palette/categories buttons, no marquee), and gearset rows used static FitText for name and level/ilvl instead of scrolling on hover. Brings it in line with the AppHeader.DrawTitleWithReserve + Marquee.DrawLeftAuto pattern used everywhere else. * fix(jobs): correct header centering, marquee hover gating, per-row string churn - AppHeader.DrawTitleWithReserve takes an explicit leftReserve (default 44f for the seven callers with a back button); Jobs has no back button and now passes 0, so the title centers in the true content width instead of shifting left. - Marquee's *Auto helpers hover-test through UiInteract.Hover instead of a raw ImGui.IsMouseHoveringRect, so rows stop scrolling under the color picker, category editor, and dropdowns that call UiInteract.BlockThisFrame. - JobEntry now builds its row ids once in the constructor instead of JobsApp concatenating them every row, every frame.
Resolves the conflicts XeldarAlz#73 and XeldarAlz#74 created. - AppHeader.DrawTitleWithReserve now carries both new optional parameters (style from this branch, leftReserve from XeldarAlz#73). - LinkshellRow keeps this branch's timeReserve subtraction on top of master's UiInteract.Hover gate. - Dailies, Timers and Message drop master's row hover locals: the rows moved to Marquee.DrawLeftAuto, which hit-tests internally, so the locals were dead (and Message's shadowed an inner declaration). - Tetris keeps the outerMargin extraction with master's gated hover. - Music keeps the showAuthor branch with master's gated hover. Also converts the 15 raw ImGui.IsMouseHoveringRect hit tests this branch reintroduced to UiInteract.Hover. Master holds the invariant that the call only appears inside UiInteract; leaving them raw would regress the occlusion fix for every text row this branch touches.
|
Pushed a merge of master onto this branch ( Conflict resolutions, all "keep both":
One change beyond the conflicts: this branch predates #74, so it reintroduced 15 raw Threads are all resolved and it is mergeable again. Pull before you push anything further. |
Summary
Fixes a batch of text truncation, hover-scroll, and layout overlap bugs reported across the app (Photos, Notes, Timers, Dailies, Activity, Fishing, Market, Clock, Aethergram, Velvet, Music, Health, Yellow Pages, Muster, Direct Messages, Linkshells, Collections, and the three arcade mini-games), plus a couple of framework-level bugs found along the way that were causing some of them.
Root causes found
Most of these bugs traced back to a small number of repeating patterns rather than being independent one-offs:
Marqueecalls (title + subtitle). Hovering either line scrolled both. Fixed by giving each line its own hover check, usingMarquee.DrawLeftAuto/DrawCenteredAutowhere possible.MarketApp.Detail.cs's hero card fix.Typography.DrawCentered's auto-wrap heuristic. The no-maxWidthoverload estimates a safe wrap width from the current ImGui window's edges relative to the text's center point. That assumption breaks for anything not roughly centered in a full-size window: a small host window (the minimized-phone icon), or an element sitting near the edge of a multi-column layout. Found three independent instances of this (Yellow Pages intent-tile category count, the minimized-phone notification badge, hover tooltips in general). Fixed each call site by bypassing the auto-wrap path with an explicit-widthMarqueecall or a manual measure-and-draw, rather than patching the heuristic itself (too many other call sites depend on its current behavior to change it globally without a full audit).height * 0.5), not just be some positive number, or the text visually crowds the curve.Per-area changes
Typography.FitTexttruncation toMarqueehover-scroll wherever text could realistically overflow, applying the shared-hover and unclamped-sibling fixes above where relevant. This includes Muster's host name/status/meta text (MusterApp.Detail.cs,.Directory.cs,.Manage.cs,MusterCard.cs), the DM/Aethergram thread header name and subtitle (MessageApp.Thread.cs,AethergramApp.Thread.cs), and a Velvet comment timestamp that could overlap a review badge.DrawIntent's header (the screen you land on from Go Somewhere/Hire Someone/Join Something) now reserves space for the scope pill instead of using a plain centered title.DrawRailCard(the "Open Now" rail) converted toMarquee. The intent tile's category count no longer goes throughTypography.DrawCentered's auto-wrap path.LinkshellRow's title width reservation only accounted for the mute-bell icon, never the timestamp drawn on the same row; now reserves the timestamp's measured width first.GameHud.PillWidth(and asizeScaleparameter onPill/ScorePill) so HUD layout can be computed from a pill's real measured width instead of guessed fixed offsets, which is what was causing Score/Level/Best to overlap the Hold/Next preview slots and each other. Watersort and Breakout's HUD rows now solve their layout as one group (fixed anchors define a middle zone, flexible elements fit inside it) rather than two independent one-sided clamps that could fight each other. Tetris's HUD went through several rounds of layout iteration; final shape is Hold/Next in the corners (fixed size, since their piece-preview rendering assumes a fixed slot size), Restart in the gap between them, and Level/Score/Best as their own row below, spanning the full board width for maximum room against large scores. Breakout's top bar was changed to match Beat's shape (Restart pinned to a corner independent of the score pills, lives shown as a vertical 3-slot indicator instead of a horizontal row) per direct request.HoverTooltip: wrap-width calculation now uses the viewport's bounds instead of the current ImGui window's content region, since tooltips render on the foreground draw list and can extend past a small host window.StepperField: chevron button width now clamps to a fraction of the actual rect width instead of a fixed constant, so it can't exceed the available space on a narrow rect.AppHeader.DrawTitleWithReserve: added an optionalTextStyleparameter so callers with a non-default title size (Photos) can use the shared helper instead of duplicating its logic inline.Test plan
dotnet buildclean after every change in this batch