Skip to content

v0.34.0

Choose a tag to compare

@github-actions github-actions released this 28 Oct 01:18
· 4 commits to main since this release
0eddfba

What changed and why

0.34.0 adds a fifth package, CvInspect.Avalonia: the display control and property editor of CvInspect.Wpf, for
Avalonia, so a host can show frames, overlays and teaching shapes on Linux as well as Windows (Linux is
checked headless in CI only so far — see the package's section below). To make
that possible without two copies of the same logic, the UI-independent parts of the WPF controls moved into the core package —
mostly as internal code, plus one public move: the property editor's row view-models and their builder now live in CvInspect.
Both display controls also get three theme keys consumers asked for (the image-area background, the no-image text color and the
toolbar icon color), and the no-image text now follows a language switch at once.

Take this release if you want the display on Avalonia, want the image area, the no-image text or the toolbar icons to follow
your theme, switch the UI language at run time, or want to build property-editor rows without WPF.

Upgrading from 0.33.0:

  • Raise all your CvInspect packages together. CvInspect.Wpf 0.34.0 requires CvInspect >= 0.34.0; keeping the core on
    0.33.x stops the restore with NU1605. CvInspect.Imaging and CvInspect.Imaging.Gev have no code change in this release — only the
    version, the core dependency and the package README's package list move.
  • No code change is needed. Code and XAML built against 0.33 keep working (see Breaking).
  • One default changes on screen: the toolbar icons without an accent now take the text color the control inherits instead of the
    button style's text color. In most themes they are the same color. A dark WPF host whose theme styles controls but not the
    Window gets black icons — see ToolbarForeground below.
  • If a source object of a property editor has a hand-written PropertyChanged accessor that walks its own handler list, read
    "Changed" below.

Breaking

Nothing breaks at the source or binary level. One move, with what it can still change:

Core — the property editor's rows moved from CvInspect.Wpf into CvInspect

CvPropGroupVm, CvPropRowVm and its seven row types (Bool, Num, Str, Enum, Action, List, Nested), CvPropRowBldr
and the four notification records (CvPropCommittedEvt, CvPropActionExecutingEvt, CvPropActionExecutedEvt,
CvPropActionFailedEvt) are now in the core package, with the same names and the same namespace (CvInspect.Controls).
CvInspect.Wpf forwards all 14 types (TypeForwardedTo), so assemblies and compiled XAML built against 0.33 resolve them.

  • Checked: the public metadata of 0.33.0 and 0.34 compared with no mismatch; the 14 forwards are pinned by a regression test.
  • What can still change: the types' assembly is now CvInspect, so anything that records an assembly-qualified type name, or asks a
    row type for its Assembly, sees the new assembly. Nothing in CvInspect does that.
  • A core-only or non-WPF host can now build the same rows itself with CvPropRowBldr.Build. The builder is reflection-based: under
    IL2CPP managed stripping keep the option types (for example with link.xml), or rows silently go missing.

Added

Core — CvPropRowBldr.Detach(groups)

Unsubscribes rows from their source at once and drops their hooks. It is final: detached rows never write again. Call it only on rows
you built yourself — on an editor's live Groups it silently throws away later edits. The editors call it whenever they rebuild their
rows (Source, ExecuteText or ShowDesc changes). CvPropRowBldr.Build itself is not new — it was public in CvInspect.Wpf and now
lives in the core, usable without WPF.

Core — CvLoc.Changed

Raised when what CvLoc.T returns may have changed: Culture set to a different value, Resolver assigned, or Reload(). It runs
on the thread that made the change, outside the lock; a subscriber that throws is logged as a warning and does not reach the caller
or the other subscribers. A change made inside a handler (a handler that calls Reload(), say) is not notified again, so handlers
cannot recurse without end. Both CvDispCtrls listen to it while loaded, so the no-image text switches language at once — before, it
kept the old language until the next repaint (a frame or a theme switch). A consumer found this in a real Avalonia window and saw the
fix work there; the WPF control had the same structure and got the same fix, checked by reading only (its test suite runs without a
window, where the control is never loaded). Nothing to do on the host side.

Known limit, unchanged: CvPropEditCtrl reads its labels, group headers and the action-button text when it builds its rows, so after a
language switch they change only when it rebuilds — assigning the same Source object again does nothing; set Source to null and
back, or change ShowDesc or ExecuteText.

Wpf and Avalonia — three theme keys for CvDispCtrl

Key constant Key string Property Default when neither is set Paints
ViewBackgroundKey CvDispViewBackgroundBrush ViewBackground the control's Background (#2A2A2A, or what the host set) image area around the picture and the no-image screen
PlaceholderForegroundKey CvDispPlaceholderForegroundBrush PlaceholderForeground #9E9E9E no-image title and load hint
ToolbarForegroundKey CvDispToolbarForegroundBrush ToolbarForeground the text color the control inherits (TextElement.Foreground) toolbar icons without an accent (📸 ⛶ ➕ ➖ 🧹, a released ✋)

The same names and the same source order (instance property, then key, then default) in both packages, so a host moving between
them keeps its color dictionary. A host with a light theme adds the first two keys to that theme's dictionary only.
PlaceholderForeground takes a solid-color brush only (other brush types keep the default and log a warning), because the text is
drawn from the core draw list's ARGB color. The named overlay colors were chosen against a dark view.

ToolbarForeground changes a default. Before, the icons took the button theme's or style's text color; a consumer on the Semi
theme, which paints button text in its brand color, saw every icon come out as an accent. Now the default is the inherited text color.
On Avalonia the color also holds with the pointer over a button and while it is pressed, where themes paint the inside of the button
template directly. Disabled buttons keep the theme's disabled look (no icon color is set on them); ⏯ and a pressed ✋ stay white.

  • The default toolbar background is a fixed light #FAFAFA. A dark theme should set ToolbarBackgroundKey as well, or give the
    icons a dark color through this key.
  • WPF hosts: the inherited text color is often not themed — a theme library that styles controls but not the Window leaves it
    at the system text color (black). A dark WPF host in that situation now gets black icons and should set this key or the window's
    Foreground.

Consumers on pre-release packages: one applied the background key (#E6E6E6) and saw it take effect; another ran the toolbar key on
the Semi theme in a real Avalonia window, light and dark, normal, pointer-over and pressed, and saw the key's color hold.

New package — CvInspect.Avalonia (first release)

CvDispCtrl and CvPropEditCtrl for Avalonia, in CvInspect.Avalonia.Controls (not the WPF package's namespace, so one project can
reference both). Same member names and meanings as CvInspect.Wpf, including the seven theme keys; the differences — ToolbarDock is
Avalonia.Controls.Dock, no message box (ImageFileFailed event and a log warning instead), file dialogs through StorageProvider,
theme keys also follow theme-variant switches, and others — are listed in its README. Toolbar icons are vector paths, so no emoji or
symbol font is needed.

  • net8.0 only (Avalonia 12 has no netstandard build), Avalonia 12.1.4 or later. Of Avalonia the package references only
    Avalonia itself (plus CvInspect); the application picks the platform (Avalonia.Desktop), renderer, theme and fonts. Keep every Avalonia.* package on the same
    version
    — a lower Avalonia.Desktop mixes versions without any warning.
  • What has been checked: a headless test suite in CI, on Windows and Linux — Skia drawing into an off-screen frame, input raised
    by the tests; zoom and label size also at render scalings 1.25 and 1.5. 77/77 on both (CI run 40610669722). One consumer has run it
    in a real window on one Windows development PC with a live camera and the mouse.
  • What has not: a Linux desktop, a known GPU renderer, high-DPI screens, macOS; in that real window, the right-click menu, the
    property editor's action rows and shape dragging.
  • Limits, also in its README: frame upload costs more than in WPF (Gray8 and Bgr24 are converted to BGRA; on one development PC a
    2448×2048 frame took about 1.9 / 3.5 ms back to back and 2.9 / 4.7 ms with idle gaps, against 0.08–1.6 ms for the WPF upload on the
    same PC; a consumer's real-window figures are in the README with their conditions). Avalonia's assemblies are unsigned, so a Windows
    PC enforcing Smart App Control can block them. Avalonia's build tooling (Avalonia.BuildServices) sends build statistics, also from
    projects that reference only this package; set AVALONIA_TELEMETRY_OPTOUT on build machines to opt out (ignored with an Accelerate
    Community or Trial license key). This package does not turn it off for you.

Samples — an Avalonia demo

samples/CvInspect.Demo.Avalonia is the WPF demo's Avalonia counterpart, sharing its view-model (sources, recipe, tools and editor).
It is in the repository only; the release's downloadable exe stays the WPF demo. In both demos, a --webcam argument that matches no
camera now keeps its "not found" notice on the status line after the synthetic source starts — before, the next status overwrote it.

Changed

Wpf — the property editor's change subscription

The editor follows the source's PropertyChanged through the core's weak subscription instead of WPF's PropertyChangedEventManager.
Notifications still arrive synchronously, on the thread that raised them. What differs is clean-up: after a dropped editor's rows are
collected, one small bridge object stays on the source and removes itself the next time that source raises PropertyChanged
(WPF's manager cleaned up when another subscription was made). Opening and dropping editors many times on a long-lived POCO that
rarely notifies, without changing Source, leaves that many bridges until it notifies; they hold neither rows nor controls.
That self-removal runs inside the source's raise. Ordinary field-like events are safe; a hand-written accessor that iterates its own
handler list must copy it before invoking, or it can throw "collection was modified" at that raise (read from the code, not
reproduced). Two consumers checked their sources on a pre-release package and found no such accessor.

Internal — the UI-independent parts of the display moved into the core

View transform, shape dragging, render geometry, the draw list and text-measure port, the frame buffer, status-bar text, command
state, image-file encode and decode rules, theme constants, the context-menu model and the property editor's wiring are now internal
code in the core (Display/), linked as source into both UI packages. No public surface changed and no behavior change is intended.
The first two steps (view transform, dragging, render geometry, draw list) were checked against the previous build: screen golden
images byte-identical (680 hashes after the first step, 4088 frames after the second, 300 drags each), and the WPF transform matrices
bit-identical (200 fits + 50 identities). The rest (frame buffer, command state, file rules, menu model, editor wiring) is covered by
the regression suites only. On a WPF host, a teaching-shape drag, an overlay, right-click load and save, and the camera buttons are
worth one look after upgrading.

Version

Minor: 0.34.0. Public API was added (the Avalonia package, CvLoc.Changed, CvPropRowBldr.Detach, three theme keys with their
properties) and one public move (the property-editor rows, forwarded).

Checks

  • dotnet build CvInspect.sln -c Release --no-incremental reports 0 warnings (an incremental build reports none when it recompiles nothing)
  • main is an ancestor of this branch (the release-pr-guard job verifies it)
  • the tag will be created on the merge commit, main merged back into dev afterwards, and dev bumped to the next -dev version
  • CvInspect.Avalonia is a new package id: the nuget.org trusted-publishing policy (owner kintaein, glob CvInspect*, scope "push
    new packages and package versions", repository cmir79/CvInspect, workflow publish.yml, active) allows its first push
  • decided — ship as is and watch (it fails the same way on v0.33.0, which has run without trouble in the field; it appeared after the
    move to a new development PC): on a local .NET 10 runtime (roll-forward; CI is .NET 8 and has always passed it) the core test
    ReconnectingCamStartDuringOurOwnStopDoesNotRebuild fails 8 of 20 isolated runs, in order ② — GrabbingChanged arrives as
    [True, True, False] while the camera ends live. v0.33.0 fails it at the same 8/20, so it is not from this release; whether it
    is the test's timing or a real ordering race in ReconnectingCam (a host could show "stopped" while live) is not yet known
  • after publish, all five ids show 0.34.0 at https://api.nuget.org/v3-flatcontainer/<id>/index.json before consumers are told
Run Commit Result
CI run 40425622253 cb34214 Windows build warnings 0; core 200/200, Wpf 65/65; Linux core 200/200
CI run 40432256485 818ee10 Windows warnings 0; core 208/208, Wpf 70/70; Linux core 208/208
CI run 40438575927 6d9dc0c Windows warnings 0; core 227/227, Wpf 71/71; Linux core 227/227
CI run 40448798532 515697b Windows warnings 0; core 241/241, Wpf 71/71; Linux core 241/241; CvInspect.Avalonia builds and packs (5 nupkg)
CI run 40452573991 e994d97 core 241/241, Wpf 71/71, Avalonia 70/70; Linux core 241/241, Avalonia 70/70 (first run)
CI run 40457427444 cb286c3 core 241/241, Wpf 71/71, Avalonia 72/72; Linux core 241/241, Avalonia 72/72
CI run 40459599064 75dbe62 core 241/241, Wpf 71/71, Avalonia 75/75; Linux core 241/241, Avalonia 75/75
CI run 40610669722 6944d46 core 243/243, Wpf 72/72, Avalonia 77/77; Linux core 243/243, Avalonia 77/77
CI run 40613205503 a03a052 (release head) core 243/243, Wpf 72/72, Avalonia 77/77; Linux core 243/243, Avalonia 77/77

Pre-release packages applied by consumers on their own machines (their measurements; details on their side):

  • 0.34.0-dev from CI run 40432256485 (818ee10, before the no-image text key and the Avalonia package), two WPF consumers, no source
    change on their side: solution builds with no warnings (non-incremental), property editor open / edit / commit / Source swap /
    action button as in 0.33, no hand-written PropertyChanged accessor, no direct CvDispCtrl.Background; one also applied the
    background key.
  • 0.34.0-dev from CI run 40610669722 (6944d46), one Avalonia consumer, Semi theme, Release single-file build: no warnings
    (non-incremental); toolbar key held in light and dark, normal / pointer-over / pressed; pressed ✋ white on its accent; disabled look
    while the window was disabled; the no-image text switched language without another repaint. Not seen: ⏯ white, a button disabled
    by its own command, real-camera runs on that build.