Skip to content

Add LevelsControl, a levels adjustment over a histogram - #536

Merged
matt-edmondson merged 1 commit into
mainfrom
claude/project-thread-a7ic2a
Sep 30, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
claude/project-thread-a7ic2a

Conversation

@matt-edmondson

@matt-edmondson matt-edmondson commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Matt · project thread

Closes #499

This PR is part of the widget stack: #567 → #536 → #539 → #540 → #542. It targets #567's branch, so its diff is the levels work alone. Merge #567 first.

Before: a levels control had to be built from Histogram and HandleTrack by hand. The caller also had to derive gamma from a grey handle and write its own transfer function to apply to pixels. That transfer function could drift from what the handles showed.

After: ImGuiWidgets.LevelsControl(label, bins, seriesCount, ref levels, size, seriesColors) draws a histogram with black, grey and white input handles. Under it are an output ramp with black and white handles and a one-line readout. It edits a caller-owned LevelsAdjustment. LevelsAdjustment.Apply is the same function the handles describe, so the curve on screen and the curve applied to an image cannot disagree. Grey point and gamma follow the Photoshop convention: the midpoint is gamma 1, and moving it toward black brightens.

How:

  • LevelsAdjustment is a readonly record struct holding:
    • Apply, Normalized, GammaFromGreyPoint and GreyPointFromGamma, implemented as the issue specifies.
    • Internal WithInputHandles and WithOutputHandles. When black and white stay put, WithInputHandles reads the drag as a grey move and changes only gamma. When either one moves, gamma is kept and the grey handle follows.
  • Both handle rows are HandleTracks, so the handles stay ordered and one 8-bit step apart. The input range is kept two steps wide so the grey handle always has room.
  • Probe names: label/histogram, label/input, label/outputRamp and label/output. All sit inside a ScopedId(label).
  • Demo: LevelsDemo.cs is registered in DemoSections.AdvancedDemos after ImageCanvas. It builds a luminance histogram of the ktsu logo, then redraws the logo through Apply whenever the levels change.
  • Gallery: a LevelsControl tile in the data and signals sheet.
  • Docs: a new "Image and Colour" group in the widgets README, plus the matching lines in CLAUDE.md and the root README.

Validation (Release):

  • ImGui.Widgets.Tests: 415/415 passed, including 22 new LevelsAdjustmentTests.
  • ImGui.Widgets.UITests: 418/418 passed, including 7 new LevelsControlTests. One of these reads the ramp's pixels to confirm it runs dark to light.
  • ImGuiWidgetsDemo.UITests: 36/36 passed, including the new LevelsDemo_DraggingTheBlackPointChangesTheLevels.
  • WidgetGallery.UITests: 6/6 passed, including --check and a full render.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LXUsRiHnKs6HCgLAbC1L6D

@matt-edmondson matt-edmondson self-assigned this Sep 29, 2026
Comment thread examples/ImGuiWidgetsDemo/GridDemo.cs Fixed
Comment thread examples/ImGuiWidgetsDemo/SearchBoxDemo.cs Fixed
Also folds in:
- Register the levels demo in the demo section registry

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HgjMCJ9MQRmUk6c8KABDYH
@matt-edmondson
matt-edmondson force-pushed the claude/project-thread-a7ic2a branch from 6cb9f33 to 9944b4e Compare September 30, 2026 10:44
@matt-edmondson
matt-edmondson changed the base branch from main to claude/project-thread-wmrk2b September 30, 2026 10:44
@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.

Domain widgets Tier 1: add LevelsControl (Histogram + HandleTrack black/grey/white points)

2 participants