Skip to content

[patch] Record the Hexa vs ktsu widget verdict - #339

Merged
matt-edmondson merged 1 commit into
mainfrom
claude/record-issues-defects-n6p37v
Aug 28, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
claude/record-issues-defects-n6p37v

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Refs #338.

CLAUDE.md said seven widget pairs "both survive on purpose until the comparison tab settles which to keep". The comparison tab shipped in #337; the verdict never got written down. This writes it down, and changes no widget code.

Nothing is obsoleted here. Retiring public API is a breaking change and that call is yours — this records what the decision is actually between, so it can be made on facts rather than on the pair list.

Five of the seven are not duplicates

Pair Why not
DividerContainer vs HorizontalSplitter/VerticalSplitter A retained layout container owning a list of DividerZones with per-zone draw callbacks, persisted sizes (GetSizes/SetSizesFromList), an onResized callback and nesting — versus one stateless drag handle mutating a ref float. The comparison tab can't even show them side by side; its splitter row points at the Advanced Demos tab for the container.
Tree vs IconTreeNode Tree is a ScopedAction drawing connector lines around nested content: no label, no collapsing, no ID-stack interaction. IconTreeNode is a real collapsible node with an icon glyph and flags, and the caller must TreePop(). They compose rather than compete — which is why TreeTests already drives both in one class.
RadialProgressBar/SkeletonLoader vs BufferingBar/Spinner Four different widgets, not two pairs: determinate radial (plus RadialCountdown/RadialCountUp), determinate linear, indeterminate spinner, shimmering placeholder. The only overlap is "determinate progress", where radial vs linear is a visual choice.
TextCentered vs TextCenteredV/H/VH Alignment.Center builds a container of (ContentRegionAvail.X, contentSize.Y) — its vertical extent is the content's own height, so vertical centring is a no-op and TextCentered is horizontal-only. It equals TextCenteredH and nothing else. TextCenteredV/VH have no ktsu counterpart; TextCenteredWithin(text, size, clip) with ellipsis clipping has no Hexa counterpart.
ImageCentered vs ImageCenteredV/H/VH Same shape, plus a hard difference the demo already comments on: ImageCentered returns bool for a click, the Hexa three return void. ImageCenteredWithin and ImageScaleTo are each unique to their side.

Two are genuine

Switch vs ToggleSwitch — identical signature. Three differences, all favouring Switch: it calls ImGuiProbes.MarkItem; it animates from ImGui.GetIO().DeltaTime rather than Hexa's clock, so it needs none of the TickAnimationClockIfUnpumped machinery ToggleSwitch requires to avoid rendering inverted after its first click in a pumpless app; and it draws the visible label itself.

Combo vs EnumCombo — only Combo<TEnum> overlaps; the ISemanticString and string collection overloads are unique. The enum overloads differ in naming (raw Enum.GetNames vs Hexa's ComboEnumHelper<T>.GetName, which is where a display-name override would come from), probe marking, and constraint (where TEnum : Enum vs where T : struct, Enum). If nothing depends on Hexa's naming, EnumCombo is the one to retire.

The through-line

Only the ktsu originals are probe-visible. Switch and Combo are the only two widgets in either family that call ImGuiProbes.MarkItem — SwitchTests and ComboTests need zero Mark calls, while every Hexa-backed suite marks the widget itself or reaches it by geometry. That is the most consequential difference between the two families and a reason to prefer a ktsu original in an app you intend to UI-test.

Changes

  • CLAUDE.md: replaces the "both survive on purpose" sentence with a link to a new Hexa-backed vs ktsu widgets section carrying the table above.
  • examples/ImGuiWidgetsDemo/HexaWidgetsDemo.cs: one line at the top of the comparison tab noting that most rows are not duplicates, pointing at that section.

Verification

dotnet build clean, 0 warnings.

ImGuiWidgetsDemo.UITests reports 12 of 28 failing both with and without this change — identical counts, so nothing here moved them. The root cause is environmental rather than a defect: examples/ImGuiWidgetsDemo/ktsu.png is a Git LFS pointer, git-lfs is not installed in this sandbox, so it was never smudged and ImageSharp fails to decode it (UnknownImageFormatException, with PNG absent from the decoder list). Every failing test is one that reaches a tab loading that texture. CI has git-lfs, so this should not reproduce there.


Generated by Claude Code

CLAUDE.md said seven widget pairs "both survive on purpose until the
comparison tab settles which to keep". The comparison tab shipped; the
verdict never got written down. This writes it down.

Five of the seven are not duplicates on inspection:

- DividerContainer is a retained layout container owning a list of zones
  with per-zone draw callbacks, persisted sizes and nesting. A Splitter is
  one stateless drag handle over a ref float. The comparison tab cannot
  even show them side by side.
- Tree is a ScopedAction that draws connector lines around nested content:
  no label, no collapsing, no ID stack. IconTreeNode is a real collapsible
  node requiring TreePop(). They compose rather than compete, which is why
  TreeTests already drives both in one class.
- RadialProgressBar / SkeletonLoader / BufferingBar / Spinner are four
  different widgets, not two pairs.
- Alignment.Center builds a container of (ContentRegionAvail.X,
  contentSize.Y), so its vertical extent is the content's own height and
  vertical centring is a no-op. TextCentered is therefore equivalent to
  TextCenteredH alone; TextCenteredV/VH and TextCenteredWithin's ellipsis
  clipping have no counterpart on the other side.
- ImageCentered returns a click where the Hexa three return void, and
  ImageCenteredWithin / ImageScaleTo are each unique to their side.

Two are genuine, with a recommended survivor:

- Switch over ToggleSwitch: same signature, but Switch marks itself for
  probes, animates from ImGui's own delta time rather than Hexa's clock
  (so it needs none of the TickAnimationClockIfUnpumped machinery), and
  draws its own label.
- Combo over EnumCombo on the enum overload, unless Hexa's display-name
  handling is wanted -- Combo shows raw Enum.GetNames and marks itself,
  EnumCombo routes through ComboEnumHelper and does not.

The through-line is that only the ktsu originals call
ImGuiProbes.MarkItem, so every Hexa-backed widget must be marked by the
test itself or reached by geometry. SwitchTests and ComboTests need no
Mark call; every Hexa-backed suite does.

Nothing is obsoleted here. Retiring public API is a breaking change and
that call belongs to the maintainer; this records what the decision is
between.

Refs #338

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DTHNXgSNEHUSQ5KMLgivno
@sonarqubecloud

Copy link
Copy Markdown

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.

2 participants