diff --git a/.github/workflows/rendering-ci.yml b/.github/workflows/rendering-ci.yml index 3a5d08dc..74b93db9 100644 --- a/.github/workflows/rendering-ci.yml +++ b/.github/workflows/rendering-ci.yml @@ -63,7 +63,40 @@ env: CMAKE_BUILD_PARALLEL_LEVEL: "2" jobs: + scope: + name: Validation scope + runs-on: ubuntu-latest + outputs: + profile: ${{ steps.select.outputs.profile }} + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Test and select validation scope + id: select + shell: pwsh + env: + BASE_REVISION: ${{ github.event.pull_request.base.sha || github.event.before }} + HEAD_REVISION: ${{ github.event.pull_request.head.sha || github.sha }} + FORCE_FULL: ${{ github.event_name == 'workflow_dispatch' }} + IS_PULL_REQUEST: ${{ github.event_name == 'pull_request' }} + run: | + ./tests/ci/Test-ValidationScope.ps1 + if ($env:FORCE_FULL -eq 'true' -or $env:BASE_REVISION -match '^0+$') { + $selection = ./tests/ci/Select-ValidationScope.ps1 -Full + } else { + git fetch --no-tags origin $env:BASE_REVISION $env:HEAD_REVISION + if ($LASTEXITCODE -ne 0) { throw 'The exact validation comparison could not be fetched.' } + $selection = ./tests/ci/Select-ValidationScope.ps1 -BaseRevision $env:BASE_REVISION -HeadRevision $env:HEAD_REVISION ` + -PullRequest:($env:IS_PULL_REQUEST -eq 'true') + } + "profile=$($selection.profile)" >> $env:GITHUB_OUTPUT + '## Selected validation scope' >> $env:GITHUB_STEP_SUMMARY + ($selection | ConvertTo-Json -Depth 5) >> $env:GITHUB_STEP_SUMMARY + managed: + needs: scope + if: needs.scope.outputs.profile == 'full' name: Managed / ${{ matrix.os }} runs-on: ${{ matrix.os }} timeout-minutes: 90 @@ -103,6 +136,7 @@ jobs: if-no-files-found: error rendering: + needs: scope if: github.event_name != 'workflow_dispatch' || inputs.native_product_acceptance name: ${{ matrix.platform }} runs-on: ${{ matrix.os }} @@ -170,6 +204,7 @@ jobs: run: | dotnet restore entry/InnoEngine.Editor/InnoEngine.Editor.csproj -p:Configuration=Debug --disable-parallel -nr:false if ($LASTEXITCODE -ne 0) { throw 'The Debug Editor dependency restore failed.' } + if ('${{ needs.scope.outputs.profile }}' -eq 'editor') { exit 0 } dotnet restore entry/InnoEngine.Editor/InnoEngine.Editor.csproj -p:Configuration=Release --disable-parallel -nr:false if ($LASTEXITCODE -ne 0) { throw 'The Release Editor dependency restore failed.' } dotnet restore '${{ matrix.player_project }}' -p:Configuration=Release ` @@ -217,7 +252,7 @@ jobs: - name: Build host Editor Release id: native_release - if: ${{ !cancelled() && steps.native_debug.outcome == 'success' }} + if: ${{ !cancelled() && needs.scope.outputs.profile == 'full' && steps.native_debug.outcome == 'success' }} shell: pwsh run: | dotnet run --project "entry/InnoEngine.Build/InnoEngine.Build.csproj" --no-build -- editor --configuration Release 2>&1 | @@ -246,7 +281,12 @@ jobs: if: ${{ !cancelled() && steps.build_entry.outcome == 'success' }} shell: pwsh run: | - dotnet build InnoEngine.sln --configuration SourceDebug --disable-build-servers -m:1 -nr:false ` + $source = 'InnoEngine.sln' + if ('${{ needs.scope.outputs.profile }}' -eq 'editor') { + $source = Join-Path $PWD 'artifacts/acceptance/ci-build/contracts.slnf' + ./tests/ci/New-ValidationSolutionFilter.ps1 -OutputPath $source + } + dotnet build $source --configuration SourceDebug --disable-build-servers -m:1 -nr:false ` -p:UseSharedCompilation=false '-bl:artifacts/acceptance/ci-build/source-debug.binlog' 2>&1 | Tee-Object -FilePath 'artifacts/acceptance/ci-build/source-debug.log' if ($LASTEXITCODE -ne 0) { throw 'SourceDebug build failed.' } @@ -267,7 +307,7 @@ jobs: run: dotnet run --project "entry/InnoEngine.Build/InnoEngine.Build.csproj" --no-build -- verify . - name: Run complete test suite - if: ${{ !cancelled() && steps.source.outcome == 'success' && steps.player_contract.outcome == 'success' }} + if: ${{ needs.scope.outputs.profile == 'full' && !cancelled() && steps.source.outcome == 'success' && steps.player_contract.outcome == 'success' }} shell: pwsh run: | $properties = Join-Path $PWD '${{ matrix.product_properties }}' @@ -288,6 +328,16 @@ jobs: if ($LASTEXITCODE -ne 0) { throw "Target test closure compilation failed." } ./tests/Invoke-IsolatedTests.ps1 -Configuration SourceDebug -Target '${{ matrix.build_target }}' -ProductProperties $properties + - name: Run affected Editor contract and workflow suites + if: ${{ needs.scope.outputs.profile == 'editor' && !cancelled() && steps.source.outcome == 'success' && steps.player_contract.outcome == 'success' }} + shell: pwsh + run: | + $output = Join-Path $env:RUNNER_TEMP 'InnoEditorChecks' + foreach ($profile in @('Contracts', 'Workflows')) { + ./tests/Invoke-EditorUiAcceptance.ps1 -Profile $profile -EditorOnly ` + -ArtifactsPath $output -ResultsDirectory 'artifacts/acceptance/ci-tests' + } + - name: Generate source-independent Player Support Pack if: ${{ !cancelled() && steps.native_release.outcome == 'success' }} shell: pwsh diff --git a/AGENTS.md b/AGENTS.md index 509cd4a8..266e9671 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -337,3 +337,9 @@ public void AAA( - Presentation preparation, drawing and publication form one owned operation. Reentry and retirement during that operation must fail before releasing resources. A callback failure ends only its owned native frame, preserves the original failure and never publishes partial draw data; it must not clear another context's stacks or lower native assertions. - Native presentation fixtures must create and enter an `EditorUiSession`, explicitly compose their feature/presentation owners, and resolve the exact service under test. Asynchronous shutdown fixtures must retry the public Pending retirement protocol until owned cleanup completes; they cannot rely on continuation timing or remove resource-release assertions. - Presentation input snapshots expose physical Core modifier semantics. Reverse native shortcut normalization at the presentation boundary using the owned context configuration; do not interpret normalized Control/Super flags as physical keys or add shared-layer OS detection. Native input fixtures explicitly select their conventions and cover both modifier policies and native modes. + +- Content-sized modals prepare one coherent frame snapshot and measure it before opening. Explicitly sized resizable windows prepare after current native input establishes their content bounds. Never invoke arbitrary drawing callbacks twice for measurement or rely on the previous message height. +- Shared dialog widgets own text wrapping, progress, bounded body scrolling and action spacing. Domain callers consume those controls and shared metrics; they must not compensate with empty lines, arbitrary padding or a second scroll owner. Escape action behavior is explicit. +- Workflow progress and cancellation are bound to the original owner and operation identity. Late callbacks cannot overwrite a newer request or a cancellation state, and progress presentation cannot weaken publication or generation retirement. + +- CI and local acceptance must follow the actual changed owners. Use scoped Editor verification for bounded UI changes; retain full verification for build, platform, backend, SDK, shared runtime or unknown owners. Record omitted checks explicitly and never bypass production validation to shorten CI. diff --git a/docs/architecture/EDITOR_UI_DESIGN_STANDARD.md b/docs/architecture/EDITOR_UI_DESIGN_STANDARD.md index d8ed91dc..f17006ab 100644 --- a/docs/architecture/EDITOR_UI_DESIGN_STANDARD.md +++ b/docs/architecture/EDITOR_UI_DESIGN_STANDARD.md @@ -116,3 +116,20 @@ Settings 的一次 Apply 复用单一 History transaction,所有 dirty owner `EditorUiInput` 的 Control/Super 表示物理修饰键,不继承原生控件内部的快捷键归一化。呈现边界依据当前 Context 的键盘配置还原这些值,列表选择复用同一快照语义,平台仍通过 `EditorKeyboardPolicy` 选择 primary modifier。原生文本控件继续使用该 Context 的输入习惯;测试必须显式声明自己的键盘配置,并覆盖 Control/Super 与两种原生模式的组合,不能依赖 runner 的默认值。 最终报告分别评价架构、组织、状态与生命周期、抽象、复用、样式、扩展、交互、Undo/Redo、菜单和颗粒度;每项列出证据与限制。目录整齐、测试数量或正常启动不能代替视觉、输入、重复 reload、资源收敛和成对性能验收。 + +## 动态 Modal 的状态与尺寸 + +- 窗口尺寸、换行和绘制使用本帧同一快照,不依赖上一条消息的高度。 +- 准备只读取和测量;实际动作由原领域 owner 校验 operation 后执行。禁止双次绘制回调测量。 +- 统一 metrics 表达 padding、item spacing、按钮高度和字体尺度。业务 Modal 不通过额外空行、固定大高度或零散数字补偿布局。 +- 消息与详情共用一个正文滚动 owner,操作行保持可达。Child 不重复承担父窗口已经提供的外层 padding。 +- 明确区分声明尺寸、自适应尺寸及用户调整尺寸;部分指定尺寸也必须得到正确解释。 +- 当前帧内容增长、缩短、空文本、动作变化及非整数尺度都属于必要回归。 + +### 按职责选择 CI 验收 + +Engine CI 根据完整 Git 变更集合选择检查,不能按 issue 编号或为了节省时间临时跳过失败项。仅涉及 Editor 创作层(包括脚本 reload owner)及对应测试、文档时使用 Editor 范围:Debug Editor、真实原生 smoke、Editor 契约与工作流、架构和 Wiki 检查。Release、NativeAOT 还原、十次热构建、其他领域完整测试及 Player Support Pack 留给完整范围。SDK、工程图、build、platform、backend、共享 Runtime 或未知 owner 的变化保守选择完整范围。手动工作流仍执行完整范围。 + +脚本 `tests/ci/Select-ValidationScope.ps1` 只编排验收,不改变生产构建或缓存校验。移动文件同时核对旧 owner 和新 owner;选择理由与省略项写入 GitHub job summary。Editor 范围不等于完整产品矩阵通过;完整源码和 Player contract 编译仍服务于当前架构/Wiki 的真实引用验证,不执行 Player 导出或 Support Pack 生产。 + +UI 范围的生产源码检查由当前 Solution 生成 169 个生产工程的 `.slnf`,引用闭包仍由 MSBuild 求值,不编译全部无关测试工程。只有通过完整 Git 差异证明为标准 SDK 工程中、相同无条件引用边的 `PrivateAssets=compile` 收紧时,才允许保留 Editor 范围;新增引用、包、TFM、SDK、条件或构建目标变化仍走完整范围。PR 使用 merge base,push 使用 before/head,避免把目标分支的无关改动混进 PR 检查。 diff --git a/docs/editor/Inno.Editor.Assets.md b/docs/editor/Inno.Editor.Assets.md index 8d22acb0..065caa4e 100644 --- a/docs/editor/Inno.Editor.Assets.md +++ b/docs/editor/Inno.Editor.Assets.md @@ -113,6 +113,10 @@ AssetDraftDocuments 的 Replace/ReplaceMany 立即记录中立 bytes,不延迟 批量删除和移动先验证整个选择,再将被选父目录覆盖的子条目归一化,最后用现有 History transaction 原子执行。后续失败自动恢复先前步骤。安装源始终只读。 +## Sample Import 呈现快照 + +`AssetSampleImportModule.progress` 在原有进度锁内一次捕获 `AssetSampleImportProgress`;后台验证观察者绑定具体操作,退休后不再接收进度。`Cancel(operationId)` 校验当前请求,并在取消底层工作之前发布不可被普通进度覆盖的取消状态。成功状态在发布及 payload 释放完成后设置;History、回滚和依赖退休仍由原事务负责。 + ## 当前源码公开 API 清单 此清单对应当前 SDK 求值与源码符号;内部类型不构成公开 API。 @@ -224,23 +228,34 @@ AssetDraftDocuments 的 Replace/ReplaceMany 立即记录中立 bytes,不延迟 - + - - + - - + - -| API 与源码 | 契约与参数 | 返回值 | 重要异常 | -| --- | --- | --- | --- | -| [`public sealed class Inno.Editor.Assets.AssetCreationMenuAttribute : System.Attribute`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L13) | Declares the source name, extension, and menu placement that cannot be inferred from an type alone. | — | — | -| [`public Inno.Editor.Assets.AssetCreationMenuAttribute.AssetCreationMenuAttribute(string id, string menuPath, string extension, string defaultName, int groupOrder = 0, int itemOrder = 0, bool separatorBeforeGroup = false)`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L42) | Creates one asset creation menu declaration.
`id`: Globally stable template identifier.
`menuPath`: Slash-delimited path below the File Browser Create menu.
`extension`: Native source extension, including its leading dot.
`defaultName`: Default source name without an extension or numeric suffix.
`groupOrder`: Stable order of the top-level category below Create.
`itemOrder`: Stable order of the leaf within its immediate category.
`separatorBeforeGroup`: Whether the top-level category starts after a separator. | — | `System.ArgumentException`: Thrown when an identifier, path, source name, or native extension is invalid. | + + + + + + + + + + + + + + +| API | 职责与参数 | 返回语义 | 失败条件 | +|---|---|---|---| +| [`public sealed class Inno.Editor.Assets.AssetCreationMenuAttribute : System.Attribute`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L13) | Declares the source name, extension, and menu placement that cannot be inferred from an Inno.Assets.AssetObject type alone. | — | — | +| [`public Inno.Editor.Assets.AssetCreationMenuAttribute.AssetCreationMenuAttribute(string id, string menuPath, string extension, string defaultName, int groupOrder = 0, int itemOrder = 0, bool separatorBeforeGroup = false)`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L42) | Creates one asset creation menu declaration.
`id`: Globally stable template identifier.
`menuPath`: Slash-delimited path below the File Browser Create menu.
`extension`: Native source extension, including its leading dot.
`defaultName`: Default source name without an extension or numeric suffix.
`groupOrder`: Stable order of the top-level category below Create.
`itemOrder`: Stable order of the leaf within its immediate category.
`separatorBeforeGroup`: Whether the top-level category starts after a separator. | — | `System.ArgumentException`: Thrown when an identifier, path, source name, or native extension is invalid. | | [`public string Inno.Editor.Assets.AssetCreationMenuAttribute.id { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L84) | Gets the globally stable template identifier. | — | — | | [`public string Inno.Editor.Assets.AssetCreationMenuAttribute.menuPath { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L89) | Gets the slash-delimited path below the File Browser Create menu. | — | — | | [`public string Inno.Editor.Assets.AssetCreationMenuAttribute.extension { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L94) | Gets the native source extension, including its leading dot. | — | — | @@ -251,26 +266,26 @@ AssetDraftDocuments 的 Replace/ReplaceMany 立即记录中立 bytes,不延迟 | [`public abstract class Inno.Editor.Assets.AssetCreationTemplate`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L124) | Produces the detached initial value for one authorable native asset source. | — | — | | [`public abstract System.Type Inno.Editor.Assets.AssetCreationTemplate.assetType { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L129) | Gets the concrete asset type produced by this template. | — | — | | [`public abstract Inno.Assets.AssetObject Inno.Editor.Assets.AssetCreationTemplate.Create()`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L137) | Creates a detached default value that has not been imported or published. | A new asset value owned by the caller. | — | -| [`public virtual byte[] Inno.Editor.Assets.AssetCreationTemplate.Encode(Inno.Editor.Assets.AssetCreationContext context, Inno.Assets.AssetObject asset)`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L156) | Encodes the detached initial value into the source representation owned by this template.
`context`: Creation services scoped to the current Asset source pipeline.
`asset`: The exact value returned by . | Complete source bytes ready for an atomic File Browser create operation. | — | -| [`protected Inno.Editor.Assets.AssetCreationTemplate.AssetCreationTemplate()`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L124) | Inherited or compiler-provided contract. | — | — | +| [`public virtual byte[] Inno.Editor.Assets.AssetCreationTemplate.Encode(Inno.Editor.Assets.AssetCreationContext context, Inno.Assets.AssetObject asset)`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L156) | Encodes the detached initial value into the source representation owned by this template.
`context`: Creation services scoped to the current Asset source pipeline.
`asset`: The exact value returned by Inno.Editor.Assets.AssetCreationTemplate.Create. | Complete source bytes ready for an atomic File Browser create operation. | — | +| [`protected Inno.Editor.Assets.AssetCreationTemplate.AssetCreationTemplate()`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L124) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public sealed class Inno.Editor.Assets.AssetCreationContext`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L169) | Provides source encoding services to one detached Asset creation template invocation. | — | — | -| [`public Inno.Editor.Assets.AssetCreationContext.AssetCreationContext(Inno.Assets.Pipeline.AssetSourceStore sources)`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L180) | Creates a context over the source serializer owned by the active Asset pipeline.
`sources`: Source serializer carrying the active reference context. | — | — | -| [`public byte[] Inno.Editor.Assets.AssetCreationContext.EncodeNative(Inno.Assets.AssetObject asset)`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L191) | Encodes an Asset value through the current native structured source serializer.
`asset`: Detached Asset value to encode. | Complete native source bytes, including the concrete serialized type identity. | — | -| [`public abstract class Inno.Editor.Assets.AssetCreationTemplate where TAsset : Inno.Assets.AssetObject, new() : Inno.Editor.Assets.AssetCreationTemplate`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L204) | Creates a default-constructed native source for an authorable asset type.
`TAsset`: Concrete serializable asset type. | — | — | +| [`public Inno.Editor.Assets.AssetCreationContext.AssetCreationContext(Inno.Assets.Pipeline.AssetSourceStore sources)`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L180) | Creates a context over the source serializer owned by the active Asset pipeline.
`sources`: Source serializer carrying the active reference context. | — | — | +| [`public byte[] Inno.Editor.Assets.AssetCreationContext.EncodeNative(Inno.Assets.AssetObject asset)`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L191) | Encodes an Asset value through the current native structured source serializer.
`asset`: Detached Asset value to encode. | Complete native source bytes, including the concrete serialized type identity. | — | +| [`public abstract class Inno.Editor.Assets.AssetCreationTemplate where TAsset : Inno.Assets.AssetObject, new() : Inno.Editor.Assets.AssetCreationTemplate`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L204) | Creates a default-constructed native source for an authorable asset type.
`TAsset`: Concrete serializable asset type. | — | — | | [`public override sealed System.Type Inno.Editor.Assets.AssetCreationTemplate.assetType { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L210) | Gets the asset type created by this Editor template. | — | — | | [`public override Inno.Assets.AssetObject Inno.Editor.Assets.AssetCreationTemplate.Create()`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L218) | Creates a value using this implementation's validated inputs. | The validated asset object that represents the completed operation. | — | | [`protected virtual TAsset Inno.Editor.Assets.AssetCreationTemplate.CreateAsset()`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L226) | Creates the initial detached value, allowing specialized deterministic defaults. | A new asset value owned by the caller. | — | -| [`protected Inno.Editor.Assets.AssetCreationTemplate.AssetCreationTemplate()`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L204) | Inherited or compiler-provided contract. | — | — | -| [`public sealed class Inno.Editor.Assets.AssetDraftDocuments where TAsset : Inno.Assets.AssetObject : System.IDisposable`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L19) | Owns detached native asset drafts with shared document, History, recovery and explicit-save semantics.
`TAsset`: Native source type edited by the consuming feature. | — | — | -| [`public Inno.Editor.Assets.AssetDraftDocuments.AssetDraftDocuments(Inno.Assets.Pipeline.AssetPipeline assets, Inno.Core.Serialization.SerializationRegistry serialization, Inno.Editor.Interactions.EditorInteractions interactions, string providerId, string historyKind, string extension, string label)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L57) | Creates a feature-owned draft store; call Start after document services become available.
`assets`: Owner of source identities, serialization and import.
`serialization`: Host registry for neutral History and recovery records.
`interactions`: Shared documents and History services.
`providerId`: Stable unique document provider identifier.
`historyKind`: Stable protocol handled by the feature's registered History handler.
`extension`: Native source extension including its leading dot.
`label`: Human-readable singular asset kind. | — | — | -| [`public Inno.Editor.Assets.AssetDraftDocuments.Draft Inno.Editor.Assets.AssetDraftDocuments.GetDraft(System.Guid assetId)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L95) | Gets host-owned neutral presentation state for an open document.
`assetId`: Persistent source identity. | Read-only presentation state; it contains no live asset or extension objects. | — | -| [`public System.Guid Inno.Editor.Assets.AssetDraftDocuments.Open(Inno.Assets.AssetPath path)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L105) | Opens a native asset source in the shared document service without revealing a second Inspector.
`path`: Source path, including sources with failed imports. | The persistent asset identity used for subsequent draft operations. | — | -| [`public TAsset Inno.Editor.Assets.AssetDraftDocuments.Read(System.Guid assetId)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L124) | Reads a detached current-generation value; callers must never mutate its referenced canonical assets.
`assetId`: Open asset identity. | A detached editable asset whose changes have not been published. | — | -| [`public void Inno.Editor.Assets.AssetDraftDocuments.Replace(System.Guid assetId, TAsset candidate, string? mergeKey = null)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L137) | Updates the open draft through shared History without saving or publishing a runtime asset.
`assetId`: Open asset identity.
`candidate`: Detached edited asset.
`mergeKey`: The current gesture key, or null for an independent discrete edit. | — | — | -| [`public void Inno.Editor.Assets.AssetDraftDocuments.ReplaceMany(System.Collections.Generic.IReadOnlyDictionary candidates, string? mergeKey = null)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L157) | Records a fully validated selection sample atomically in the shared History.
`candidates`: Detached candidates keyed by their persistent source identity.
`mergeKey`: The owning gesture key, or null for a discrete edit. | — | — | -| [`public bool Inno.Editor.Assets.AssetDraftDocuments.TryMergeHistory(Inno.Editor.Interactions.EditorHistoryChange older, Inno.Editor.Interactions.EditorHistoryChange newer, out Inno.Editor.Interactions.EditorHistoryChange? merged)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L221) | Combines adjacent samples of the same document and gesture without retaining live assets.
`older`: The preceding owned record.
`newer`: The subsequent owned record.
`merged`: Receives a new independent payload when the records form a contiguous edit. | True when both records describe the same continuous value change. | — | -| [`public void Inno.Editor.Assets.AssetDraftDocuments.ValidateHistory(Inno.Editor.Interactions.EditorHistoryChange change, Inno.Editor.Interactions.EditorHistoryDirection direction)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L252) | Validates a feature's neutral History record without changing the draft.
`change`: Record owned by the shared History service.
`direction`: Requested traversal direction. | — | — | -| [`public void Inno.Editor.Assets.AssetDraftDocuments.ApplyHistory(Inno.Editor.Interactions.EditorHistoryChange change, Inno.Editor.Interactions.EditorHistoryDirection direction)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L270) | Applies a previously validated neutral record; failed recovery leaves the draft unchanged.
`change`: Record owned by the shared History service.
`direction`: Requested traversal direction. | — | — | +| [`protected Inno.Editor.Assets.AssetCreationTemplate.AssetCreationTemplate()`](../../src/composition/editor/features/Inno.Editor.Assets/Creation/AssetCreationTemplate.cs#L204) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public sealed class Inno.Editor.Assets.AssetDraftDocuments where TAsset : Inno.Assets.AssetObject : System.IDisposable`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L19) | Owns detached native asset drafts with shared document, History, recovery and explicit-save semantics.
`TAsset`: Native source type edited by the consuming feature. | — | — | +| [`public Inno.Editor.Assets.AssetDraftDocuments.AssetDraftDocuments(Inno.Assets.Pipeline.AssetPipeline assets, Inno.Core.Serialization.SerializationRegistry serialization, Inno.Editor.Interactions.EditorInteractions interactions, string providerId, string historyKind, string extension, string label)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L57) | Creates a feature-owned draft store; call Start after document services become available.
`assets`: Owner of source identities, serialization and import.
`serialization`: Host registry for neutral History and recovery records.
`interactions`: Shared documents and History services.
`providerId`: Stable unique document provider identifier.
`historyKind`: Stable protocol handled by the feature's registered History handler.
`extension`: Native source extension including its leading dot.
`label`: Human-readable singular asset kind. | — | — | +| [`public Inno.Editor.Assets.AssetDraftDocuments.Draft Inno.Editor.Assets.AssetDraftDocuments.GetDraft(System.Guid assetId)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L95) | Gets host-owned neutral presentation state for an open document.
`assetId`: Persistent source identity. | Read-only presentation state; it contains no live asset or extension objects. | — | +| [`public System.Guid Inno.Editor.Assets.AssetDraftDocuments.Open(Inno.Assets.AssetPath path)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L105) | Opens a native asset source in the shared document service without revealing a second Inspector.
`path`: Source path, including sources with failed imports. | The persistent asset identity used for subsequent draft operations. | — | +| [`public TAsset Inno.Editor.Assets.AssetDraftDocuments.Read(System.Guid assetId)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L124) | Reads a detached current-generation value; callers must never mutate its referenced canonical assets.
`assetId`: Open asset identity. | A detached editable asset whose changes have not been published. | — | +| [`public void Inno.Editor.Assets.AssetDraftDocuments.Replace(System.Guid assetId, TAsset candidate, string? mergeKey = null)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L137) | Updates the open draft through shared History without saving or publishing a runtime asset.
`assetId`: Open asset identity.
`candidate`: Detached edited asset.
`mergeKey`: The current gesture key, or null for an independent discrete edit. | — | — | +| [`public void Inno.Editor.Assets.AssetDraftDocuments.ReplaceMany(System.Collections.Generic.IReadOnlyDictionary candidates, string? mergeKey = null)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L157) | Records a fully validated selection sample atomically in the shared History.
`candidates`: Detached candidates keyed by their persistent source identity.
`mergeKey`: The owning gesture key, or null for a discrete edit. | — | — | +| [`public bool Inno.Editor.Assets.AssetDraftDocuments.TryMergeHistory(Inno.Editor.Interactions.EditorHistoryChange older, Inno.Editor.Interactions.EditorHistoryChange newer, out Inno.Editor.Interactions.EditorHistoryChange? merged)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L221) | Combines adjacent samples of the same document and gesture without retaining live assets.
`older`: The preceding owned record.
`newer`: The subsequent owned record.
`merged`: Receives a new independent payload when the records form a contiguous edit. | True when both records describe the same continuous value change. | — | +| [`public void Inno.Editor.Assets.AssetDraftDocuments.ValidateHistory(Inno.Editor.Interactions.EditorHistoryChange change, Inno.Editor.Interactions.EditorHistoryDirection direction)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L252) | Validates a feature's neutral History record without changing the draft.
`change`: Record owned by the shared History service.
`direction`: Requested traversal direction. | — | — | +| [`public void Inno.Editor.Assets.AssetDraftDocuments.ApplyHistory(Inno.Editor.Interactions.EditorHistoryChange change, Inno.Editor.Interactions.EditorHistoryDirection direction)`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L270) | Applies a previously validated neutral record; failed recovery leaves the draft unchanged.
`change`: Record owned by the shared History service.
`direction`: Requested traversal direction. | — | — | | [`public void Inno.Editor.Assets.AssetDraftDocuments.Start()`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L402) | Registers the feature provider with the headless document ownership service. | — | — | | [`public void Inno.Editor.Assets.AssetDraftDocuments.Update()`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L412) | Imports explicit saves and reconciles source changes without owning UI gesture lifetimes. | — | — | | [`public void Inno.Editor.Assets.AssetDraftDocuments.Dispose()`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L478) | Preserves unsaved recovery and unregisters the current feature provider. | — | — | @@ -282,44 +297,44 @@ AssetDraftDocuments 的 Replace/ReplaceMany 立即记录中立 bytes,不延迟 | [`public string Inno.Editor.Assets.AssetDraftDocuments.Draft.error { get; internal set; }`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L602) | Gets the latest source, save or import diagnostic. | — | — | | [`public bool Inno.Editor.Assets.AssetDraftDocuments.Draft.isDirty { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Documents/AssetDraftDocuments.cs#L606) | Gets whether detached bytes differ from the saved baseline. | — | — | | [`public sealed class Inno.Editor.Assets.AssetEditingModule : Inno.Editor.Core.EditorModule`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.Creation.cs#L13) | Handles asset creation actions in the Editor file browser. | — | — | -| [`public Inno.Assets.Pipeline.AssetFileEntry Inno.Editor.Assets.AssetEditingModule.CreateDirectory(Inno.Assets.AssetPath parent)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.Creation.cs#L27) | Creates a uniquely named directory and records its removal and restoration in shared History.
`parent`: An existing writable source directory. | The indexed identity of the newly created directory. | `System.InvalidOperationException`: The source is read-only, unavailable, or cannot retain the History entry. | -| [`public Inno.Assets.Pipeline.AssetFileEntry Inno.Editor.Assets.AssetEditingModule.CreateSource(Inno.Assets.AssetPath path, System.ReadOnlySpan bytes)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.Creation.cs#L75) | Creates a native or ordinary-text asset source as one recoverable shared-history operation.
`path`: A new file in an existing writable asset directory.
`bytes`: Complete source bytes supplied by the feature's native writer. | The indexed source identity, even when its first import reports a source error. | `System.IO.IOException`: The source already exists, has no existing parent, or cannot be installed.
`System.InvalidOperationException`: The source mount is unavailable/read-only or history cannot retain the change. | -| [`public Inno.Editor.Assets.AssetEditingModule.AssetEditingModule(Inno.Editor.Interactions.EditorInteractions interactions, Inno.Assets.Pipeline.AssetPipeline pipeline, Inno.Plugins.Authoring.PluginEnvironment plugins, Inno.Extensibility.Types.TypeCatalog types, Inno.Core.Logging.LogRouter logs)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L50) | Creates the asset editing service for one authoring generation.
`interactions`: The active editor interaction entry point.
`pipeline`: The isolated authoring asset pipeline used by browser operations.
`plugins`: The active Plugin catalog that authoritatively identifies Plugin-owned source mounts.
`types`: The active type catalog used to build extension registry snapshots.
`logs`: The application log router used for Asset Browser operation diagnostics. | — | `System.ArgumentNullException`: Thrown when any required service is . | +| [`public Inno.Assets.Pipeline.AssetFileEntry Inno.Editor.Assets.AssetEditingModule.CreateDirectory(Inno.Assets.AssetPath parent)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.Creation.cs#L27) | Creates a uniquely named directory and records its removal and restoration in shared History.
`parent`: An existing writable source directory. | The indexed identity of the newly created directory. | `System.InvalidOperationException`: The source is read-only, unavailable, or cannot retain the History entry. | +| [`public Inno.Assets.Pipeline.AssetFileEntry Inno.Editor.Assets.AssetEditingModule.CreateSource(Inno.Assets.AssetPath path, System.ReadOnlySpan bytes)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.Creation.cs#L75) | Creates a native or ordinary-text asset source as one recoverable shared-history operation.
`path`: A new file in an existing writable asset directory.
`bytes`: Complete source bytes supplied by the feature's native writer. | The indexed source identity, even when its first import reports a source error. | `System.IO.IOException`: The source already exists, has no existing parent, or cannot be installed.
`System.InvalidOperationException`: The source mount is unavailable/read-only or history cannot retain the change. | +| [`public Inno.Editor.Assets.AssetEditingModule.AssetEditingModule(Inno.Editor.Interactions.EditorInteractions interactions, Inno.Assets.Pipeline.AssetPipeline pipeline, Inno.Plugins.Authoring.PluginEnvironment plugins, Inno.Extensibility.Types.TypeCatalog types, Inno.Core.Logging.LogRouter logs)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L50) | Creates the asset editing service for one authoring generation.
`interactions`: The active editor interaction entry point.
`pipeline`: The isolated authoring asset pipeline used by browser operations.
`plugins`: The active Plugin catalog that authoritatively identifies Plugin-owned source mounts.
`types`: The active type catalog used to build extension registry snapshots.
`logs`: The application log router used for Asset Browser operation diagnostics. | — | `System.ArgumentNullException`: Thrown when any required service is null. | | [`public Inno.Editor.Interactions.EditorInteractions Inno.Editor.Assets.AssetEditingModule.interactions { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L71) | Gets the editor interaction owner used by source operations. | — | — | | [`public Inno.Assets.Pipeline.AssetPipeline Inno.Editor.Assets.AssetEditingModule.pipeline { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L77) | Gets the authoritative authoring pipeline; mutations must use its existing ownership protocol. | — | — | | [`public System.Collections.Generic.IReadOnlyList Inno.Editor.Assets.AssetEditingModule.creationTemplates { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L81) | Gets the current immutable creation menu declarations without retaining template instances. | — | — | -| [`public bool Inno.Editor.Assets.AssetEditingModule.CanCreateAsset(string directory, string templateId)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L96) | Checks that a creation template and writable destination are available.
`directory`: The source-relative writable destination directory.
`templateId`: The stable identity of a discovered creation template. | True when the request is accepted; otherwise false. | — | -| [`public Inno.Assets.Pipeline.AssetFileEntry Inno.Editor.Assets.AssetEditingModule.CreateAsset(string directory, string templateId)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L120) | Creates and imports a source using a discovered template and records the committed change.
`directory`: The source-relative writable destination directory.
`templateId`: The stable identity of a discovered creation template. | The committed source identity, or a validation result describing why the operation is unavailable. | — | -| [`public bool Inno.Editor.Assets.AssetEditingModule.IsPluginSource(Inno.Assets.AssetSourceId source)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L170) | Determines whether the active Plugin catalog owns a source mount.
`source`: The source mount identity to query. | True when the request is accepted; otherwise false. | — | -| [`public bool Inno.Editor.Assets.AssetEditingModule.IsPluginRoot(Inno.Assets.Pipeline.AssetFileEntry entry)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L181) | Determines whether an indexed entry is the root of an installed Plugin.
`entry`: The currently indexed source identity. | True when the request is accepted; otherwise false. | — | -| [`public bool Inno.Editor.Assets.AssetEditingModule.TryCreateContext(Inno.Editor.Core.EditorContext editor, string relativePath, out Inno.Editor.Assets.AssetEditorContext? context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L203) | Captures the currently indexed source and extension metadata for one immediate operation.
`editor`: The current editor context used only during this invocation.
`relativePath`: The isolated source-relative path to resolve.
`context`: Receives the current source snapshot, or null when the source is unavailable. | True when the request is accepted; otherwise false. | — | -| [`public bool Inno.Editor.Assets.AssetEditingModule.Open(Inno.Editor.Assets.AssetEditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L230) | Opens a source using its current asset editor extension and reports rejected or failed opens.
`context`: The immutable metadata captured for this immediate source operation. | True when the request is accepted; otherwise false. | — | -| [`public Inno.Editor.Interactions.EditorValidationResult Inno.Editor.Assets.AssetEditingModule.ValidateRename(Inno.Editor.Assets.AssetEditorContext context, string newName)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L260) | Validates a requested name without modifying the source.
`context`: The immutable metadata captured for this immediate source operation.
`newName`: The requested entry name without its protected file extension. | The committed source identity, or a validation result describing why the operation is unavailable. | — | -| [`public void Inno.Editor.Assets.AssetEditingModule.Rename(Inno.Editor.Assets.AssetEditorContext context, string newName)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L278) | Renames a source atomically and records its reversible history payload.
`context`: The immutable metadata captured for this immediate source operation.
`newName`: The requested entry name without its protected file extension. | — | — | -| [`public bool Inno.Editor.Assets.AssetEditingModule.CanMoveToDirectory(string sourcePath, string targetDirectory)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L314) | Checks whether a source can move into the destination without a cycle or name collision.
`sourcePath`: The current isolated source-relative path.
`targetDirectory`: The isolated destination directory. | True when the request is accepted; otherwise false. | — | -| [`public Inno.Assets.Pipeline.AssetFileEntry Inno.Editor.Assets.AssetEditingModule.MoveToDirectoryWithHistory(string sourcePath, string targetDirectory, Inno.Editor.Interactions.IEditorHistory history)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L334) | Moves a source and records the committed mutation in the supplied history.
`sourcePath`: The current isolated source-relative path.
`targetDirectory`: The isolated destination directory.
`history`: The authoritative history that receives the committed mutation. | The committed source identity, or a validation result describing why the operation is unavailable. | — | -| [`public bool Inno.Editor.Assets.AssetEditingModule.DeleteWithHistory(Inno.Editor.Assets.AssetEditorContext asset, Inno.Editor.Interactions.IEditorHistory history)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L411) | Deletes a source with a recoverable archive and records the committed mutation.
`asset`: The captured source metadata to validate and delete.
`history`: The authoritative History receiving this mutation. | True when the request is accepted; otherwise false. | — | -| [`public void Inno.Editor.Assets.AssetEditingModule.SelectPath(string relativePath)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L462) | Selects the current source identity without retaining an indexed entry across generations.
`relativePath`: The isolated source-relative path to resolve. | — | — | -| [`public bool Inno.Editor.Assets.AssetEditingModule.TryCreateDragData(Inno.Editor.Assets.AssetEditorContext context, out Inno.Editor.Interactions.EditorDragData? data)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L481) | Creates identity-based drag data when the current extension permits dragging.
`context`: The immutable metadata captured for this immediate source operation.
`data`: Receives identity-based drag data, or null when dragging is unavailable. | True when the request is accepted; otherwise false. | — | -| [`protected override void Inno.Editor.Assets.AssetEditingModule.OnStart(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L502) | Initializes this feature when its owning runtime becomes active.
`context`: The context that supplies state and services for this operation. | — | — | -| [`protected override void Inno.Editor.Assets.AssetEditingModule.OnStop(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L513) | Stops this feature before its owning runtime releases the active generation.
`context`: The context that supplies state and services for this operation. | — | — | +| [`public bool Inno.Editor.Assets.AssetEditingModule.CanCreateAsset(string directory, string templateId)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L96) | Checks that a creation template and writable destination are available.
`directory`: The source-relative writable destination directory.
`templateId`: The stable identity of a discovered creation template. | True when the request is accepted; otherwise false. | — | +| [`public Inno.Assets.Pipeline.AssetFileEntry Inno.Editor.Assets.AssetEditingModule.CreateAsset(string directory, string templateId)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L120) | Creates and imports a source using a discovered template and records the committed change.
`directory`: The source-relative writable destination directory.
`templateId`: The stable identity of a discovered creation template. | The committed source identity, or a validation result describing why the operation is unavailable. | — | +| [`public bool Inno.Editor.Assets.AssetEditingModule.IsPluginSource(Inno.Assets.AssetSourceId source)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L170) | Determines whether the active Plugin catalog owns a source mount.
`source`: The source mount identity to query. | True when the request is accepted; otherwise false. | — | +| [`public bool Inno.Editor.Assets.AssetEditingModule.IsPluginRoot(Inno.Assets.Pipeline.AssetFileEntry entry)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L181) | Determines whether an indexed entry is the root of an installed Plugin.
`entry`: The currently indexed source identity. | True when the request is accepted; otherwise false. | — | +| [`public bool Inno.Editor.Assets.AssetEditingModule.TryCreateContext(Inno.Editor.Core.EditorContext editor, string relativePath, out Inno.Editor.Assets.AssetEditorContext? context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L203) | Captures the currently indexed source and extension metadata for one immediate operation.
`editor`: The current editor context used only during this invocation.
`relativePath`: The isolated source-relative path to resolve.
`context`: Receives the current source snapshot, or null when the source is unavailable. | True when the request is accepted; otherwise false. | — | +| [`public bool Inno.Editor.Assets.AssetEditingModule.Open(Inno.Editor.Assets.AssetEditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L230) | Opens a source using its current asset editor extension and reports rejected or failed opens.
`context`: The immutable metadata captured for this immediate source operation. | True when the request is accepted; otherwise false. | — | +| [`public Inno.Editor.Interactions.EditorValidationResult Inno.Editor.Assets.AssetEditingModule.ValidateRename(Inno.Editor.Assets.AssetEditorContext context, string newName)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L260) | Validates a requested name without modifying the source.
`context`: The immutable metadata captured for this immediate source operation.
`newName`: The requested entry name without its protected file extension. | The committed source identity, or a validation result describing why the operation is unavailable. | — | +| [`public void Inno.Editor.Assets.AssetEditingModule.Rename(Inno.Editor.Assets.AssetEditorContext context, string newName)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L278) | Renames a source atomically and records its reversible history payload.
`context`: The immutable metadata captured for this immediate source operation.
`newName`: The requested entry name without its protected file extension. | — | — | +| [`public bool Inno.Editor.Assets.AssetEditingModule.CanMoveToDirectory(string sourcePath, string targetDirectory)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L314) | Checks whether a source can move into the destination without a cycle or name collision.
`sourcePath`: The current isolated source-relative path.
`targetDirectory`: The isolated destination directory. | True when the request is accepted; otherwise false. | — | +| [`public Inno.Assets.Pipeline.AssetFileEntry Inno.Editor.Assets.AssetEditingModule.MoveToDirectoryWithHistory(string sourcePath, string targetDirectory, Inno.Editor.Interactions.IEditorHistory history)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L334) | Moves a source and records the committed mutation in the supplied history.
`sourcePath`: The current isolated source-relative path.
`targetDirectory`: The isolated destination directory.
`history`: The authoritative history that receives the committed mutation. | The committed source identity, or a validation result describing why the operation is unavailable. | — | +| [`public bool Inno.Editor.Assets.AssetEditingModule.DeleteWithHistory(Inno.Editor.Assets.AssetEditorContext asset, Inno.Editor.Interactions.IEditorHistory history)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L411) | Deletes a source with a recoverable archive and records the committed mutation.
`asset`: The captured source metadata to validate and delete.
`history`: The authoritative History receiving this mutation. | True when the request is accepted; otherwise false. | — | +| [`public void Inno.Editor.Assets.AssetEditingModule.SelectPath(string relativePath)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L462) | Selects the current source identity without retaining an indexed entry across generations.
`relativePath`: The isolated source-relative path to resolve. | — | — | +| [`public bool Inno.Editor.Assets.AssetEditingModule.TryCreateDragData(Inno.Editor.Assets.AssetEditorContext context, out Inno.Editor.Interactions.EditorDragData? data)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L481) | Creates identity-based drag data when the current extension permits dragging.
`context`: The immutable metadata captured for this immediate source operation.
`data`: Receives identity-based drag data, or null when dragging is unavailable. | True when the request is accepted; otherwise false. | — | +| [`protected override void Inno.Editor.Assets.AssetEditingModule.OnStart(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L502) | Initializes this feature when its owning runtime becomes active.
`context`: The context that supplies state and services for this operation. | — | — | +| [`protected override void Inno.Editor.Assets.AssetEditingModule.OnStop(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L513) | Stops this feature before its owning runtime releases the active generation.
`context`: The context that supplies state and services for this operation. | — | — | | [`protected override void Inno.Editor.Assets.AssetEditingModule.OnDispose()`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.cs#L521) | Releases resources retained by this feature after it has stopped. | — | — | -| [`public Inno.Editor.Assets.AssetOperationValidation Inno.Editor.Assets.AssetEditingModule.ValidateDeleteSelection(Inno.Editor.Core.EditorContext editor, System.Collections.Generic.IReadOnlyList targets)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.Selection.cs#L28) | Checks the entire source selection before a batch mutation, including extension validation and read-only ownership.
`editor`: The immediate Editor context.
`targets`: Fresh source entries in selection order. | The first rejection, or a valid result when every source can be deleted. | — | -| [`public void Inno.Editor.Assets.AssetEditingModule.DeleteSelection(Inno.Editor.Core.EditorContext editor, System.Collections.Generic.IReadOnlyList targets)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.Selection.cs#L68) | Deletes minimal selected source roots in one History transaction, restoring earlier deletions if a later one fails.
`editor`: The immediate Editor context.
`targets`: Fresh selected source entries; nested entries are covered by their selected directory. | — | `System.InvalidOperationException`: Validation or a mutation fails; rollback failures remain explicit. | -| [`public bool Inno.Editor.Assets.AssetEditingModule.CanMoveSelection(System.Collections.Generic.IReadOnlyList targets, string targetDirectory)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.Selection.cs#L99) | Validates every minimal selected source and rejects destination collisions before a batch move.
`targets`: Live source entries in selection order.
`targetDirectory`: The writable project destination. | True when every source can move to a distinct destination. | — | -| [`public void Inno.Editor.Assets.AssetEditingModule.MoveSelection(System.Collections.Generic.IReadOnlyList targets, string targetDirectory)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.Selection.cs#L126) | Moves selected source roots in one transaction; a later failure restores earlier moves.
`targets`: Live entries, including descendants covered by a selected directory.
`targetDirectory`: The writable project destination. | — | `System.InvalidOperationException`: Any source or destination rejects the operation. | +| [`public Inno.Editor.Assets.AssetOperationValidation Inno.Editor.Assets.AssetEditingModule.ValidateDeleteSelection(Inno.Editor.Core.EditorContext editor, System.Collections.Generic.IReadOnlyList targets)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.Selection.cs#L28) | Checks the entire source selection before a batch mutation, including extension validation and read-only ownership.
`editor`: The immediate Editor context.
`targets`: Fresh source entries in selection order. | The first rejection, or a valid result when every source can be deleted. | — | +| [`public void Inno.Editor.Assets.AssetEditingModule.DeleteSelection(Inno.Editor.Core.EditorContext editor, System.Collections.Generic.IReadOnlyList targets)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.Selection.cs#L68) | Deletes minimal selected source roots in one History transaction, restoring earlier deletions if a later one fails.
`editor`: The immediate Editor context.
`targets`: Fresh selected source entries; nested entries are covered by their selected directory. | — | `System.InvalidOperationException`: Validation or a mutation fails; rollback failures remain explicit. | +| [`public bool Inno.Editor.Assets.AssetEditingModule.CanMoveSelection(System.Collections.Generic.IReadOnlyList targets, string targetDirectory)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.Selection.cs#L99) | Validates every minimal selected source and rejects destination collisions before a batch move.
`targets`: Live source entries in selection order.
`targetDirectory`: The writable project destination. | True when every source can move to a distinct destination. | — | +| [`public void Inno.Editor.Assets.AssetEditingModule.MoveSelection(System.Collections.Generic.IReadOnlyList targets, string targetDirectory)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditingModule.Selection.cs#L126) | Moves selected source roots in one transaction; a later failure restores earlier moves.
`targets`: Live entries, including descendants covered by a selected directory.
`targetDirectory`: The writable project destination. | — | `System.InvalidOperationException`: Any source or destination rejects the operation. | | [`public abstract class Inno.Editor.Assets.AssetEditor`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L7) | Customizes editor interactions for one imported asset type. | — | — | -| [`public virtual bool Inno.Editor.Assets.AssetEditor.CanOpen(Inno.Editor.Assets.AssetEditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L18) | Gets whether the fallback asset editor can open the supplied source entry.
`context`: The immutable source and catalog snapshot for the operation. | when can handle the entry; otherwise, . | — | -| [`public virtual void Inno.Editor.Assets.AssetEditor.Open(Inno.Editor.Assets.AssetEditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L25) | Opens the supplied asset entry when no more specific typed open action handled it.
`context`: The immutable source and catalog snapshot for the operation. | — | — | -| [`public virtual Inno.Editor.Assets.AssetOperationValidation Inno.Editor.Assets.AssetEditor.ValidateRename(Inno.Editor.Assets.AssetEditorContext context, string targetPath)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L41) | Validates a requested asset move before the AssetPipeline transaction begins.
`context`: The immutable snapshot of the source entry before the move.
`targetPath`: The normalized source-relative destination path. | A valid result when the transaction may proceed, or a diagnostic describing the rejection. | — | -| [`public virtual void Inno.Editor.Assets.AssetEditor.OnRenamed(Inno.Editor.Assets.AssetEditorContext context, string oldPath, string newPath)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L57) | Runs after an asset move transaction commits successfully.
`context`: The immutable snapshot captured before the move.
`oldPath`: The previous source-relative path.
`newPath`: The committed source-relative destination path. | — | — | -| [`public virtual Inno.Editor.Assets.AssetOperationValidation Inno.Editor.Assets.AssetEditor.ValidateDelete(Inno.Editor.Assets.AssetEditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L73) | Validates a requested asset deletion before the AssetPipeline transaction begins.
`context`: The immutable snapshot of the entry that would be deleted. | A valid result when the transaction may proceed, or a diagnostic describing the rejection. | — | -| [`public virtual void Inno.Editor.Assets.AssetEditor.OnDeleted(Inno.Editor.Assets.AssetEditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L80) | Runs after an asset deletion transaction commits successfully.
`context`: The immutable snapshot captured before the entry was deleted. | — | — | -| [`public virtual bool Inno.Editor.Assets.AssetEditor.CanStartDrag(Inno.Editor.Assets.AssetEditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L93) | Gets whether the supplied entry can begin a managed editor drag operation.
`context`: The immutable source and catalog snapshot for the entry. | when drag data can be created; otherwise, . | — | -| [`public virtual Inno.Editor.Interactions.EditorDragData Inno.Editor.Assets.AssetEditor.CreateDragData(Inno.Editor.Assets.AssetEditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L103) | Creates the managed source, preview label, and validity predicate for an asset drag.
`context`: The immutable source and catalog snapshot for the entry. | The managed drag data published by the Asset Browser. | — | -| [`protected Inno.Editor.Assets.AssetEditor.AssetEditor()`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L7) | Inherited or compiler-provided contract. | — | — | +| [`public virtual bool Inno.Editor.Assets.AssetEditor.CanOpen(Inno.Editor.Assets.AssetEditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L18) | Gets whether the fallback asset editor can open the supplied source entry.
`context`: The immutable source and catalog snapshot for the operation. | true when Inno.Editor.Assets.AssetEditor.Open(Inno.Editor.Assets.AssetEditorContext) can handle the entry; otherwise, false. | — | +| [`public virtual void Inno.Editor.Assets.AssetEditor.Open(Inno.Editor.Assets.AssetEditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L25) | Opens the supplied asset entry when no more specific typed open action handled it.
`context`: The immutable source and catalog snapshot for the operation. | — | — | +| [`public virtual Inno.Editor.Assets.AssetOperationValidation Inno.Editor.Assets.AssetEditor.ValidateRename(Inno.Editor.Assets.AssetEditorContext context, string targetPath)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L41) | Validates a requested asset move before the AssetPipeline transaction begins.
`context`: The immutable snapshot of the source entry before the move.
`targetPath`: The normalized source-relative destination path. | A valid result when the transaction may proceed, or a diagnostic describing the rejection. | — | +| [`public virtual void Inno.Editor.Assets.AssetEditor.OnRenamed(Inno.Editor.Assets.AssetEditorContext context, string oldPath, string newPath)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L57) | Runs after an asset move transaction commits successfully.
`context`: The immutable snapshot captured before the move.
`oldPath`: The previous source-relative path.
`newPath`: The committed source-relative destination path. | — | — | +| [`public virtual Inno.Editor.Assets.AssetOperationValidation Inno.Editor.Assets.AssetEditor.ValidateDelete(Inno.Editor.Assets.AssetEditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L73) | Validates a requested asset deletion before the AssetPipeline transaction begins.
`context`: The immutable snapshot of the entry that would be deleted. | A valid result when the transaction may proceed, or a diagnostic describing the rejection. | — | +| [`public virtual void Inno.Editor.Assets.AssetEditor.OnDeleted(Inno.Editor.Assets.AssetEditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L80) | Runs after an asset deletion transaction commits successfully.
`context`: The immutable snapshot captured before the entry was deleted. | — | — | +| [`public virtual bool Inno.Editor.Assets.AssetEditor.CanStartDrag(Inno.Editor.Assets.AssetEditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L93) | Gets whether the supplied entry can begin a managed editor drag operation.
`context`: The immutable source and catalog snapshot for the entry. | true when drag data can be created; otherwise, false. | — | +| [`public virtual Inno.Editor.Interactions.EditorDragData Inno.Editor.Assets.AssetEditor.CreateDragData(Inno.Editor.Assets.AssetEditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L103) | Creates the managed source, preview label, and validity predicate for an asset drag.
`context`: The immutable source and catalog snapshot for the entry. | The managed drag data published by the Asset Browser. | — | +| [`protected Inno.Editor.Assets.AssetEditor.AssetEditor()`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditor.cs#L7) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public sealed class Inno.Editor.Assets.AssetEditorAttribute : System.Attribute`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditorAttribute.cs#L8) | Associates an asset editor with an imported asset type. | — | — | -| [`public Inno.Editor.Assets.AssetEditorAttribute.AssetEditorAttribute(System.Type assetType, bool useForChildren = false, int priority = 0)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditorAttribute.cs#L25) | Creates an asset-editor registration for an imported runtime asset type.
`assetType`: The imported asset type handled by the editor.
`useForChildren`: Whether the editor may also handle assignable derived asset types.
`priority`: The tie-breaking priority after exactness and inheritance distance. | — | `System.ArgumentNullException`: Thrown when is . | +| [`public Inno.Editor.Assets.AssetEditorAttribute.AssetEditorAttribute(System.Type assetType, bool useForChildren = false, int priority = 0)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditorAttribute.cs#L25) | Creates an asset-editor registration for an imported runtime asset type.
`assetType`: The imported asset type handled by the editor.
`useForChildren`: Whether the editor may also handle assignable derived asset types.
`priority`: The tie-breaking priority after exactness and inheritance distance. | — | `System.ArgumentNullException`: Thrown when assetType is null. | | [`public System.Type Inno.Editor.Assets.AssetEditorAttribute.assetType { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditorAttribute.cs#L38) | Gets the imported asset type handled by the editor. | — | — | | [`public bool Inno.Editor.Assets.AssetEditorAttribute.useForChildren { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditorAttribute.cs#L42) | Gets whether derived asset types are accepted. | — | — | | [`public int Inno.Editor.Assets.AssetEditorAttribute.priority { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditorAttribute.cs#L46) | Gets the tie-breaking priority. | — | — | @@ -332,32 +347,43 @@ AssetDraftDocuments 的 Replace/ReplaceMany 立即记录中立 bytes,不延迟 | [`public Inno.Assets.AssetInfo? Inno.Editor.Assets.AssetEditorContext.info { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditorContext.cs#L86) | Gets the cataloged asset information when available. | — | — | | [`public System.Type? Inno.Editor.Assets.AssetEditorContext.assetType { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetEditorContext.cs#L90) | Gets the resolved imported asset type when available. | — | — | | [`public readonly record struct Inno.Editor.Assets.AssetOperationValidation : System.IEquatable`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L5) | Describes whether an editor asset operation may proceed. | — | — | -| [`public Inno.Editor.Assets.AssetOperationValidation.AssetOperationValidation(bool isValid, string message)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L16) | Creates the validation result returned before an asset transaction begins.
`isValid`: Whether the requested asset operation may proceed.
`message`: The user-facing rejection diagnostic, or an empty string for a valid result. | — | — | +| [`public Inno.Editor.Assets.AssetOperationValidation.AssetOperationValidation(bool isValid, string message)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L16) | Creates the validation result returned before an asset transaction begins.
`isValid`: Whether the requested asset operation may proceed.
`message`: The user-facing rejection diagnostic, or an empty string for a valid result. | — | — | | [`public bool Inno.Editor.Assets.AssetOperationValidation.isValid { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L27) | Gets whether the operation may proceed. | — | — | | [`public string Inno.Editor.Assets.AssetOperationValidation.message { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L31) | Gets the validation diagnostic. | — | — | | [`public static Inno.Editor.Assets.AssetOperationValidation Inno.Editor.Assets.AssetOperationValidation.valid { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L35) | Gets a successful validation result. | — | — | -| [`public static Inno.Editor.Assets.AssetOperationValidation Inno.Editor.Assets.AssetOperationValidation.Invalid(string message)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L46) | Creates a failed asset-operation validation result.
`message`: The user-facing diagnostic explaining why the operation was rejected. | An invalid validation result containing the supplied diagnostic. | — | +| [`public static Inno.Editor.Assets.AssetOperationValidation Inno.Editor.Assets.AssetOperationValidation.Invalid(string message)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L46) | Creates a failed asset-operation validation result.
`message`: The user-facing diagnostic explaining why the operation was rejected. | An invalid validation result containing the supplied diagnostic. | — | | [`public override string Inno.Editor.Assets.AssetOperationValidation.ToString()`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L5) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | -| [`public static bool Inno.Editor.Assets.AssetOperationValidation.operator !=(Inno.Editor.Assets.AssetOperationValidation left, Inno.Editor.Assets.AssetOperationValidation right)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L5) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.Assets.AssetOperationValidation.operator ==(Inno.Editor.Assets.AssetOperationValidation left, Inno.Editor.Assets.AssetOperationValidation right)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L5) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.Assets.AssetOperationValidation.operator !=(Inno.Editor.Assets.AssetOperationValidation left, Inno.Editor.Assets.AssetOperationValidation right)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L5) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Assets.AssetOperationValidation.operator ==(Inno.Editor.Assets.AssetOperationValidation left, Inno.Editor.Assets.AssetOperationValidation right)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L5) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.Assets.AssetOperationValidation.GetHashCode()`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L5) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.Assets.AssetOperationValidation.Equals(object obj)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L5) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.Assets.AssetOperationValidation.Equals(Inno.Editor.Assets.AssetOperationValidation other)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L5) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | +| [`public override bool Inno.Editor.Assets.AssetOperationValidation.Equals(object obj)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L5) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Assets.AssetOperationValidation.Equals(Inno.Editor.Assets.AssetOperationValidation other)`](../../src/composition/editor/features/Inno.Editor.Assets/Editing/AssetOperationValidation.cs#L5) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | | [`public sealed class Inno.Editor.Assets.AssetImportSettingsEdits : Inno.Editor.Core.EditorModule`](../../src/composition/editor/features/Inno.Editor.Assets/ImportSettings/AssetImportSettingsEdits.cs#L15) | Applies importer configuration through the common sidecar pipeline and stable-identity Editor history. | — | — | -| [`public Inno.Editor.Assets.AssetImportSettingsEdits.AssetImportSettingsEdits(Inno.Assets.Pipeline.AssetPipeline assets, Inno.Core.Serialization.SerializationRegistry serialization, Inno.Extensibility.Types.TypeCatalog types, Inno.Editor.Interactions.EditorInteractions interactions)`](../../src/composition/editor/features/Inno.Editor.Assets/ImportSettings/AssetImportSettingsEdits.cs#L38) | Uses the authoring owners responsible for source identity, converter generations and shared undo.
`assets`: Authoritative asset pipeline.
`serialization`: Current owner converter registry.
`types`: Current type generation owner.
`interactions`: Shared Editor history owner. | — | — | -| [`public bool Inno.Editor.Assets.AssetImportSettingsEdits.Apply(Inno.Assets.AssetPath path, Inno.Core.Serialization.ISerializable settings, string expectedFingerprint)`](../../src/composition/editor/features/Inno.Editor.Assets/ImportSettings/AssetImportSettingsEdits.cs#L65) | Saves one settings gesture, recording neutral before/after properties even when reimport reports an error.
`path`: Writable source asset path.
`settings`: Detached current-generation settings value.
`expectedFingerprint`: Sidecar fingerprint captured when editing began. | Whether the saved configuration reimported successfully; false does not mean the settings were discarded. | — | -| [`public sealed class Inno.Editor.Assets.AssetSampleImportModule : Inno.Editor.Core.EditorModule, System.IProgress`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L20) | Owns sample import validation, publication and rollback independently of its progress window. | — | — | -| [`public override bool Inno.Editor.Assets.AssetSampleImportModule.blocksFollowingUpdates { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L50) | Defers later modules while the import pins their generation or requires a Host restart. | — | — | -| [`public bool Inno.Editor.Assets.AssetSampleImportModule.isBusy { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L54) | Gets whether an import still owns validation or publication work. | — | — | -| [`public bool Inno.Editor.Assets.AssetSampleImportModule.canImport { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L58) | Gets whether the current authoring generation admits a new sample import. | — | — | -| [`public string Inno.Editor.Assets.AssetSampleImportModule.status { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L63) | Gets an immutable progress message captured under the progress owner lock. | — | — | -| [`public float Inno.Editor.Assets.AssetSampleImportModule.progress { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L75) | Gets the most recent validation progress fraction. | — | — | -| [`public void Inno.Editor.Assets.AssetSampleImportModule.Request(Inno.Assets.AssetPath source)`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L93) | Begins validating an installed sample before its source copy can be committed.
`source`: The installed sample root to validate and import. | — | `System.InvalidOperationException`: The authoring generation is busy or faulted. | -| [`public void Inno.Editor.Assets.AssetSampleImportModule.Cancel()`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L105) | Requests cancellation without releasing work that has not retired. | — | — | -| [`public void Inno.Editor.Assets.AssetSampleImportModule.Report(Inno.Scripting.Compiler.ScriptCompilationProgress value)`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L118) | Receives asynchronous compilation progress without accessing live Editor state.
`value`: The compiler stage and completion fraction. | — | — | -| [`protected override void Inno.Editor.Assets.AssetSampleImportModule.OnUpdate(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L125) | Advances completed background phases and publishes the validated import at a frame safe point.
`context`: The current Editor frame and interaction services. | — | — | -| [`protected override void Inno.Editor.Assets.AssetSampleImportModule.OnStop(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L200) | Cancels and retires pending work before the scripting and asset dependencies stop.
`context`: The stopping Editor's interaction services. | — | — | -| [`protected override void Inno.Editor.Assets.AssetSampleImportModule.OnDispose()`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L209) | Retries retirement without releasing dependencies still used by background work. | — | — | +| [`public Inno.Editor.Assets.AssetImportSettingsEdits.AssetImportSettingsEdits(Inno.Assets.Pipeline.AssetPipeline assets, Inno.Core.Serialization.SerializationRegistry serialization, Inno.Extensibility.Types.TypeCatalog types, Inno.Editor.Interactions.EditorInteractions interactions)`](../../src/composition/editor/features/Inno.Editor.Assets/ImportSettings/AssetImportSettingsEdits.cs#L38) | Uses the authoring owners responsible for source identity, converter generations and shared undo.
`assets`: Authoritative asset pipeline.
`serialization`: Current owner converter registry.
`types`: Current type generation owner.
`interactions`: Shared Editor history owner. | — | — | +| [`public bool Inno.Editor.Assets.AssetImportSettingsEdits.Apply(Inno.Assets.AssetPath path, Inno.Core.Serialization.ISerializable settings, string expectedFingerprint)`](../../src/composition/editor/features/Inno.Editor.Assets/ImportSettings/AssetImportSettingsEdits.cs#L65) | Saves one settings gesture, recording neutral before/after properties even when reimport reports an error.
`path`: Writable source asset path.
`settings`: Detached current-generation settings value.
`expectedFingerprint`: Sidecar fingerprint captured when editing began. | Whether the saved configuration reimported successfully; false does not mean the settings were discarded. | — | +| [`public sealed class Inno.Editor.Assets.AssetSampleImportModule : Inno.Editor.Core.EditorModule`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L20) | Owns sample import validation, publication and rollback independently of its progress window. | — | — | +| [`public override bool Inno.Editor.Assets.AssetSampleImportModule.blocksFollowingUpdates { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L51) | Defers later modules while the import pins their generation or requires a Host restart. | — | — | +| [`public bool Inno.Editor.Assets.AssetSampleImportModule.isBusy { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L55) | Gets whether an import still owns validation or publication work. | — | — | +| [`public bool Inno.Editor.Assets.AssetSampleImportModule.canImport { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L59) | Gets whether the current authoring generation admits a new sample import. | — | — | +| [`public Inno.Editor.Assets.AssetSampleImportProgress Inno.Editor.Assets.AssetSampleImportModule.progress { get; }`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L64) | Gets a complete immutable progress snapshot under the existing owner lock. | — | — | +| [`public void Inno.Editor.Assets.AssetSampleImportModule.Request(Inno.Assets.AssetPath source)`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L82) | Begins validating an installed sample before its source copy can be committed.
`source`: The installed sample root to validate and import. | — | `System.InvalidOperationException`: The authoring generation is busy or faulted. | +| [`public void Inno.Editor.Assets.AssetSampleImportModule.Cancel(long operationId)`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L114) | Cancels only the import observed by the presentation.
`operationId`: The current import identity captured by the caller. | — | — | +| [`protected override void Inno.Editor.Assets.AssetSampleImportModule.OnUpdate(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L126) | Advances completed background phases and publishes the validated import at a frame safe point.
`context`: The current Editor frame and interaction services. | — | — | +| [`protected override void Inno.Editor.Assets.AssetSampleImportModule.OnStop(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L202) | Cancels and retires pending work before the scripting and asset dependencies stop.
`context`: The stopping Editor's interaction services. | — | — | +| [`protected override void Inno.Editor.Assets.AssetSampleImportModule.OnDispose()`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs#L211) | Retries retirement without releasing dependencies still used by background work. | — | — | +| [`public readonly record struct Inno.Editor.Assets.AssetSampleImportProgress : System.IEquatable`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs#L18) | Contains one atomically captured sample import status.
`operationId`: The import identity within its owner.
`fraction`: The completed validation and publication fraction.
`status`: The current stage description.
`cancellationRequested`: Whether cancellation is draining owned work. | — | — | +| [`public Inno.Editor.Assets.AssetSampleImportProgress.AssetSampleImportProgress(long operationId, float fraction, string status, bool cancellationRequested)`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs#L18) | Contains one atomically captured sample import status.
`operationId`: The import identity within its owner.
`fraction`: The completed validation and publication fraction.
`status`: The current stage description.
`cancellationRequested`: Whether cancellation is draining owned work. | — | — | +| [`public long Inno.Editor.Assets.AssetSampleImportProgress.operationId { get; init; }`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs#L19) | The import identity within its owner. | — | — | +| [`public float Inno.Editor.Assets.AssetSampleImportProgress.fraction { get; init; }`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs#L20) | The completed validation and publication fraction. | — | — | +| [`public string Inno.Editor.Assets.AssetSampleImportProgress.status { get; init; }`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs#L21) | The current stage description. | — | — | +| [`public bool Inno.Editor.Assets.AssetSampleImportProgress.cancellationRequested { get; init; }`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs#L22) | Whether cancellation is draining owned work. | — | — | +| [`public override string Inno.Editor.Assets.AssetSampleImportProgress.ToString()`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs#L18) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | +| [`public static bool Inno.Editor.Assets.AssetSampleImportProgress.operator !=(Inno.Editor.Assets.AssetSampleImportProgress left, Inno.Editor.Assets.AssetSampleImportProgress right)`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs#L18) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Assets.AssetSampleImportProgress.operator ==(Inno.Editor.Assets.AssetSampleImportProgress left, Inno.Editor.Assets.AssetSampleImportProgress right)`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs#L18) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public override int Inno.Editor.Assets.AssetSampleImportProgress.GetHashCode()`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs#L18) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | +| [`public override bool Inno.Editor.Assets.AssetSampleImportProgress.Equals(object obj)`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs#L18) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Assets.AssetSampleImportProgress.Equals(Inno.Editor.Assets.AssetSampleImportProgress other)`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs#L18) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | +| [`public void Inno.Editor.Assets.AssetSampleImportProgress.Deconstruct(out long operationId, out float fraction, out string status, out bool cancellationRequested)`](../../src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs#L18) | 由 C# 编译器生成的值契约成员。 | — | — | ## 项目依赖 @@ -367,7 +393,7 @@ AssetDraftDocuments 的 Replace/ReplaceMany 立即记录中立 bytes,不延迟 | `Inno.Core.IO` | 实现依赖;不传递 compile surface | | `Inno.Core.Execution` | 实现依赖;不传递 compile surface | | `Inno.Scripting.Api` | 实现依赖;不传递 compile surface | -| `Inno.Scripting.Compiler` | 公开签名依赖 | +| `Inno.Scripting.Compiler` | 实现依赖;不传递 compile surface | | `Inno.Core.Serialization` | 公开签名依赖 | | `Inno.Core.Logging` | 公开签名依赖 | | `Inno.Extensibility.Types` | 公开签名依赖 | diff --git a/docs/editor/Inno.Editor.Core.md b/docs/editor/Inno.Editor.Core.md index cbedc027..e5fd134b 100644 --- a/docs/editor/Inno.Editor.Core.md +++ b/docs/editor/Inno.Editor.Core.md @@ -265,11 +265,20 @@ Editor 模块更新与 Reload 事务使用 Edit Session;Play Tick 和运行对 `EditorDisplayNames.Nicify` 为菜单、Inspector 与插件控件格式化标识符,不需要 ImGui session 或原生 context。空白输入得到空标签;下划线、连字符及小写到大写的边界产生空格。 +## Modal 的本帧准备契约 + +内容自适应 Modal 通过 protected `OnPrepare(EditorContext, Vector2)` 捕获本帧状态并返回所需内容尺寸。输入、输出均为已经应用当前尺度的呈现坐标,不再乘 Zoom。高度未明确声明时必须测量;无效或缺失结果会隔离该扩展并报告诊断。 + +内容自适应窗口在打开前准备;明确尺寸的可调整窗口在原生输入确定本帧内容区之后准备。两种策略每次呈现都只准备一次、绘制一次。准备只能读取快照和测量,不能构建、发布、取消或修改 History;用户动作在绘制后交回原业务 owner。 + +`initialSize` 的两个维度分别解释:正宽度即使配合零高度也有效;零宽度使用通用默认宽度;零高度使用本帧测量。显式尺寸和用户可调整尺寸保持自己的策略。公开 `Prepare` 与 `Draw` 是框架驱动入口,继续从脚本 API 排除;派生扩展实现 protected hooks。 + ## 当前源码公开 API 清单 此清单对应当前 SDK 求值与源码符号;内部类型不构成公开 API。 + @@ -279,6 +288,7 @@ Editor 模块更新与 Reload 事务使用 Edit Session;Play Tick 和运行对 + @@ -423,38 +433,40 @@ Editor 模块更新与 Reload 事务使用 Edit Session;Play Tick 和运行对 -| API 与源码 | 契约与参数 | 返回值 | 重要异常 | -| --- | --- | --- | --- | +| API | 职责与参数 | 返回语义 | 失败条件 | +|---|---|---|---| | [`public abstract class Inno.Editor.Core.EditorModal`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L10) | Defines non-dockable modal editor content. | — | — | -| [`public abstract bool Inno.Editor.Core.EditorModal.isVisible { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L15) | Gets whether the modal should currently be visible. | — | — | -| [`public virtual bool Inno.Editor.Core.EditorModal.blocksInteraction { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L20) | Gets whether the modal prevents interaction with regular editor views. | — | — | -| [`public virtual bool Inno.Editor.Core.EditorModal.canMove { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L25) | Gets whether the modal window can be moved inside the main viewport. | — | — | -| [`public virtual bool Inno.Editor.Core.EditorModal.canResize { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L30) | Gets whether the modal window can be resized by the user. | — | — | -| [`public virtual bool Inno.Editor.Core.EditorModal.allowScrolling { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L36) | Gets whether the modal window owns scrolling when its content overflows. Disable this when a child region owns all scrolling. | — | — | -| [`public virtual System.Numerics.Vector2 Inno.Editor.Core.EditorModal.initialSize { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L42) | Gets the initial modal size in unscaled editor units, or when the runtime should size the modal from its content. | — | — | -| [`public virtual System.Numerics.Vector2 Inno.Editor.Core.EditorModal.minimumSize { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L48) | Gets the minimum modal size in unscaled editor units, or when no explicit minimum is required. | — | — | -| [`public void Inno.Editor.Core.EditorModal.Draw(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L60) | Draws the modal body inside the runtime-managed centered window.
`context`: The shared editor context containing current project and frame state. | — | `System.ArgumentNullException`: Thrown when is . | -| [`protected abstract void Inno.Editor.Core.EditorModal.OnDraw(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L72) | Draws the modal body inside the runtime-managed centered window.
`context`: The shared editor context containing current project and frame state. | — | — | -| [`protected Inno.Editor.Core.EditorModal.EditorModal()`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L10) | Inherited or compiler-provided contract. | — | — | +| [`public System.Numerics.Vector2? Inno.Editor.Core.EditorModal.Prepare(Inno.Editor.Core.EditorContext context, System.Numerics.Vector2 availableContentSize)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L32) | Captures presentation state before submitting content. Content-sized windows prepare before opening; explicitly sized resizable windows prepare after current input establishes their content bounds.
`context`: The owner-thread editor context for this frame.
`availableContentSize`: The bounded content area in current presentation coordinates, already scaled. | The required content size, or null for an explicitly sized window. | `System.ArgumentNullException`: The context is null.
`System.ArgumentOutOfRangeException`: The available extent is not finite and positive. | +| [`public abstract bool Inno.Editor.Core.EditorModal.isVisible { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L46) | Gets whether the modal should currently be visible. | — | — | +| [`public virtual bool Inno.Editor.Core.EditorModal.blocksInteraction { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L51) | Gets whether the modal prevents interaction with regular editor views. | — | — | +| [`public virtual bool Inno.Editor.Core.EditorModal.canMove { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L56) | Gets whether the modal window can be moved inside the main viewport. | — | — | +| [`public virtual bool Inno.Editor.Core.EditorModal.canResize { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L61) | Gets whether the modal window can be resized by the user. | — | — | +| [`public virtual bool Inno.Editor.Core.EditorModal.allowScrolling { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L67) | Gets whether the modal window owns scrolling when its content overflows. Disable this when a child region owns all scrolling. | — | — | +| [`public virtual System.Numerics.Vector2 Inno.Editor.Core.EditorModal.initialSize { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L73) | Gets the initial modal size in unscaled editor units, or P:System.Numerics.Vector2.Zero when the runtime should size the modal from its content. | — | — | +| [`public virtual System.Numerics.Vector2 Inno.Editor.Core.EditorModal.minimumSize { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L79) | Gets the minimum modal size in unscaled editor units, or P:System.Numerics.Vector2.Zero when no explicit minimum is required. | — | — | +| [`public void Inno.Editor.Core.EditorModal.Draw(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L91) | Draws the modal body inside the runtime-managed centered window.
`context`: The shared editor context containing current project and frame state. | — | `System.ArgumentNullException`: Thrown when context is null. | +| [`protected abstract void Inno.Editor.Core.EditorModal.OnDraw(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L103) | Draws the modal body inside the runtime-managed centered window.
`context`: The shared editor context containing current project and frame state. | — | — | +| [`protected virtual System.Numerics.Vector2? Inno.Editor.Core.EditorModal.OnPrepare(Inno.Editor.Core.EditorContext context, System.Numerics.Vector2 availableContentSize)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L118) | Captures the state consumed by OnDraw and measures it without drawing or performing domain operations. Content-sized modals must return a finite, nonnegative size. Fixed-size modals may return null.
`context`: The current owner-thread context.
`availableContentSize`: The bounded, already scaled content area. | The content extent required by the captured state, or null for explicit sizing. | — | +| [`protected Inno.Editor.Core.EditorModal.EditorModal()`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs#L10) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public sealed class Inno.Editor.Core.EditorModalAttribute : System.Attribute`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModalAttribute.cs#L9) | Registers a centered editor modal for automatic discovery. | — | — | -| [`public Inno.Editor.Core.EditorModalAttribute.EditorModalAttribute(string id, string title, int order = 0)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModalAttribute.cs#L26) | Creates a centered modal registration with a stable identity and draw order.
`id`: The stable identity used to retain modal transition state across refreshes.
`title`: The visible title rendered by the modal host.
`order`: The stable ordering value when multiple modals are visible. | — | `System.ArgumentException`: Thrown when or is empty. | +| [`public Inno.Editor.Core.EditorModalAttribute.EditorModalAttribute(string id, string title, int order = 0)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModalAttribute.cs#L26) | Creates a centered modal registration with a stable identity and draw order.
`id`: The stable identity used to retain modal transition state across refreshes.
`title`: The visible title rendered by the modal host.
`order`: The stable ordering value when multiple modals are visible. | — | `System.ArgumentException`: Thrown when id or title is empty. | | [`public string Inno.Editor.Core.EditorModalAttribute.id { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModalAttribute.cs#L43) | Gets the stable modal identifier. | — | — | | [`public string Inno.Editor.Core.EditorModalAttribute.title { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModalAttribute.cs#L48) | Gets the visible modal title. | — | — | | [`public int Inno.Editor.Core.EditorModalAttribute.order { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModalAttribute.cs#L53) | Gets the stable draw order. | — | — | | [`public abstract class Inno.Editor.Core.EditorModule : System.IDisposable`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L13) | Owns optional shared state and lifecycle for one editor feature. Simple panels and actions do not need a module. | — | — | | [`public virtual bool Inno.Editor.Core.EditorModule.blocksFollowingUpdates { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L28) | Gets whether modules ordered after this module must defer their updates for the current frame. | — | — | -| [`public void Inno.Editor.Core.EditorModule.Start(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L46) | Starts the module after the containing extension generation becomes active.
`context`: The shared editor context for the active runtime. | — | `System.ArgumentNullException`: Thrown when is .
`System.ObjectDisposedException`: Thrown after the module has been disposed.
`System.InvalidOperationException`: Thrown when the module is already started. | -| [`public void Inno.Editor.Core.EditorModule.Update(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L74) | Updates the module once per editor frame before panels and modals are drawn.
`context`: The shared editor context containing the current frame state. | — | `System.ArgumentNullException`: Thrown when is .
`System.ObjectDisposedException`: Thrown after the module has been disposed.
`System.InvalidOperationException`: Thrown when the module is not started. | -| [`public void Inno.Editor.Core.EditorModule.Stop(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L102) | Stops the module before the containing extension generation is released.
`context`: The shared editor context for the runtime being stopped. | — | `System.ArgumentNullException`: Thrown when is .
`System.ObjectDisposedException`: Thrown after the module has been disposed.
`Inno.Core.Execution.RetirementPendingException`: Live work still depends on this module. Its owner must retain it and retry Stop before disposal. | -| [`protected virtual void Inno.Editor.Core.EditorModule.OnStart(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L133) | Runs after the module generation becomes active and before its first update.
`context`: The shared editor context for the active runtime. | — | — | -| [`protected virtual void Inno.Editor.Core.EditorModule.OnUpdate(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L143) | Runs once per editor frame before views are drawn.
`context`: The shared editor context containing the current frame state. | — | — | -| [`protected virtual void Inno.Editor.Core.EditorModule.OnStop(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L157) | Runs before the module generation is released and its disposable instances are destroyed.
`context`: The shared editor context for the runtime being stopped. | — | — | -| [`protected virtual void Inno.Editor.Core.EditorModule.Capture(Inno.Editor.Core.EditorState state)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L172) | Captures readable project state owned by this module.
`state`: The writable parameter that receives the complete readable state for this module. | — | — | -| [`protected virtual void Inno.Editor.Core.EditorModule.Restore(Inno.Editor.Core.EditorState state)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L187) | Restores readable project state owned by this module.
`state`: The read-only state parameter for this module. Missing or incompatible values return the fallback supplied to . | — | — | +| [`public void Inno.Editor.Core.EditorModule.Start(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L46) | Starts the module after the containing extension generation becomes active.
`context`: The shared editor context for the active runtime. | — | `System.ArgumentNullException`: Thrown when context is null.
`System.ObjectDisposedException`: Thrown after the module has been disposed.
`System.InvalidOperationException`: Thrown when the module is already started. | +| [`public void Inno.Editor.Core.EditorModule.Update(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L74) | Updates the module once per editor frame before panels and modals are drawn.
`context`: The shared editor context containing the current frame state. | — | `System.ArgumentNullException`: Thrown when context is null.
`System.ObjectDisposedException`: Thrown after the module has been disposed.
`System.InvalidOperationException`: Thrown when the module is not started. | +| [`public void Inno.Editor.Core.EditorModule.Stop(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L102) | Stops the module before the containing extension generation is released.
`context`: The shared editor context for the runtime being stopped. | — | `System.ArgumentNullException`: Thrown when context is null.
`System.ObjectDisposedException`: Thrown after the module has been disposed.
`Inno.Core.Execution.RetirementPendingException`: Live work still depends on this module. Its owner must retain it and retry Stop before disposal. | +| [`protected virtual void Inno.Editor.Core.EditorModule.OnStart(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L133) | Runs after the module generation becomes active and before its first update.
`context`: The shared editor context for the active runtime. | — | — | +| [`protected virtual void Inno.Editor.Core.EditorModule.OnUpdate(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L143) | Runs once per editor frame before views are drawn.
`context`: The shared editor context containing the current frame state. | — | — | +| [`protected virtual void Inno.Editor.Core.EditorModule.OnStop(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L157) | Runs before the module generation is released and its disposable instances are destroyed.
`context`: The shared editor context for the runtime being stopped. | — | — | +| [`protected virtual void Inno.Editor.Core.EditorModule.Capture(Inno.Editor.Core.EditorState state)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L172) | Captures readable project state owned by this module.
`state`: The writable parameter that receives the complete readable state for this module. | — | — | +| [`protected virtual void Inno.Editor.Core.EditorModule.Restore(Inno.Editor.Core.EditorState state)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L187) | Restores readable project state owned by this module.
`state`: The read-only state parameter for this module. Missing or incompatible values return the fallback supplied to Inno.Editor.Core.EditorState.Get``1(System.String,``0). | — | — | | [`protected virtual void Inno.Editor.Core.EditorModule.OnDispose()`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L195) | Releases resources owned by this module after it has stopped and left the active extension generation. | — | — | -| [`protected Inno.Editor.Core.EditorModule.EditorModule()`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L13) | Inherited or compiler-provided contract. | — | — | +| [`protected Inno.Editor.Core.EditorModule.EditorModule()`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModule.cs#L13) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public sealed class Inno.Editor.Core.EditorModuleAttribute : System.Attribute`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModuleAttribute.cs#L9) | Registers an editor feature module with a stable identity for automatic discovery. | — | — | -| [`public Inno.Editor.Core.EditorModuleAttribute.EditorModuleAttribute(string id, int order = 0)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModuleAttribute.cs#L24) | Creates a module registration with stable identity and deterministic lifecycle order.
`id`: The globally unique module identifier used for discovery diagnostics and optional persisted module state.
`order`: The ascending order used to start and update the module. | — | `System.ArgumentException`: Thrown when is empty. | +| [`public Inno.Editor.Core.EditorModuleAttribute.EditorModuleAttribute(string id, int order = 0)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModuleAttribute.cs#L24) | Creates a module registration with stable identity and deterministic lifecycle order.
`id`: The globally unique module identifier used for discovery diagnostics and optional persisted module state.
`order`: The ascending order used to start and update the module. | — | `System.ArgumentException`: Thrown when id is empty. | | [`public string Inno.Editor.Core.EditorModuleAttribute.id { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModuleAttribute.cs#L37) | Gets the stable module identifier. | — | — | | [`public int Inno.Editor.Core.EditorModuleAttribute.order { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModuleAttribute.cs#L42) | Gets the stable lifecycle order. | — | — | | [`public abstract class Inno.Editor.Core.EditorPanel`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L13) | Base class for editor panel implementations. | — | — | @@ -462,17 +474,17 @@ Editor 模块更新与 Reload 事务使用 Edit Session;Play Tick 和运行对 | [`public virtual bool Inno.Editor.Core.EditorPanel.allowScrolling { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L31) | Gets whether the presentation backend may create a scroll range for this panel window. | — | — | | [`public virtual System.Numerics.Vector2 Inno.Editor.Core.EditorPanel.initialSize { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L36) | Gets the initial floating size in UI coordinates; zero leaves native auto-sizing in control. Saved layouts take precedence. | — | — | | [`public bool Inno.Editor.Core.EditorPanel.isOpen { get; set; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L41) | Gets or sets whether panel is visible. | — | — | -| [`public void Inno.Editor.Core.EditorPanel.Attach(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L56) | Attaches the panel after its extension generation becomes active.
`context`: The shared editor context for the active runtime. | — | `System.ArgumentNullException`: Thrown when is .
`System.InvalidOperationException`: Thrown when the panel is already attached. | -| [`public void Inno.Editor.Core.EditorPanel.Detach(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L82) | Detaches the panel before its extension generation is released.
`context`: The shared editor context for the runtime being detached. | — | `System.ArgumentNullException`: Thrown when is .
`Inno.Core.Execution.RetirementPendingException`: Panel work is still active. The owner must retain the panel and its dependencies and retry detachment. | -| [`public void Inno.Editor.Core.EditorPanel.Draw(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L117) | Draws the complete dockable contents of the panel for the current frame.
`context`: The shared editor context containing current selection, focus, and frame state. | — | `System.ArgumentNullException`: Thrown when is .
`System.InvalidOperationException`: Thrown when the panel is not attached. | -| [`protected abstract void Inno.Editor.Core.EditorPanel.OnDraw(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L131) | Draws the complete dockable contents of this panel for the current frame.
`context`: The shared editor context containing current selection, focus, and frame state. | — | — | -| [`protected virtual void Inno.Editor.Core.EditorPanel.OnAttach(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L139) | Runs after the panel is attached to an active extension generation.
`context`: The shared editor context for the active runtime. | — | — | -| [`protected virtual void Inno.Editor.Core.EditorPanel.OnDetach(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L153) | Runs before the panel is detached from its active extension generation.
`context`: The shared editor context for the runtime being detached. | — | — | -| [`protected virtual void Inno.Editor.Core.EditorPanel.Capture(Inno.Editor.Core.EditorState state)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L168) | Captures readable project state owned by this panel.
`state`: The writable parameter that receives the complete readable state for this panel. | — | — | -| [`protected virtual void Inno.Editor.Core.EditorPanel.Restore(Inno.Editor.Core.EditorState state)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L183) | Restores readable project state owned by this panel.
`state`: The read-only state parameter for this panel. Missing or incompatible values return the fallback supplied to . | — | — | -| [`protected Inno.Editor.Core.EditorPanel.EditorPanel()`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L13) | Inherited or compiler-provided contract. | — | — | +| [`public void Inno.Editor.Core.EditorPanel.Attach(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L56) | Attaches the panel after its extension generation becomes active.
`context`: The shared editor context for the active runtime. | — | `System.ArgumentNullException`: Thrown when context is null.
`System.InvalidOperationException`: Thrown when the panel is already attached. | +| [`public void Inno.Editor.Core.EditorPanel.Detach(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L82) | Detaches the panel before its extension generation is released.
`context`: The shared editor context for the runtime being detached. | — | `System.ArgumentNullException`: Thrown when context is null.
`Inno.Core.Execution.RetirementPendingException`: Panel work is still active. The owner must retain the panel and its dependencies and retry detachment. | +| [`public void Inno.Editor.Core.EditorPanel.Draw(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L117) | Draws the complete dockable contents of the panel for the current frame.
`context`: The shared editor context containing current selection, focus, and frame state. | — | `System.ArgumentNullException`: Thrown when context is null.
`System.InvalidOperationException`: Thrown when the panel is not attached. | +| [`protected abstract void Inno.Editor.Core.EditorPanel.OnDraw(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L131) | Draws the complete dockable contents of this panel for the current frame.
`context`: The shared editor context containing current selection, focus, and frame state. | — | — | +| [`protected virtual void Inno.Editor.Core.EditorPanel.OnAttach(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L139) | Runs after the panel is attached to an active extension generation.
`context`: The shared editor context for the active runtime. | — | — | +| [`protected virtual void Inno.Editor.Core.EditorPanel.OnDetach(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L153) | Runs before the panel is detached from its active extension generation.
`context`: The shared editor context for the runtime being detached. | — | — | +| [`protected virtual void Inno.Editor.Core.EditorPanel.Capture(Inno.Editor.Core.EditorState state)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L168) | Captures readable project state owned by this panel.
`state`: The writable parameter that receives the complete readable state for this panel. | — | — | +| [`protected virtual void Inno.Editor.Core.EditorPanel.Restore(Inno.Editor.Core.EditorState state)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L183) | Restores readable project state owned by this panel.
`state`: The read-only state parameter for this panel. Missing or incompatible values return the fallback supplied to Inno.Editor.Core.EditorState.Get``1(System.String,``0). | — | — | +| [`protected Inno.Editor.Core.EditorPanel.EditorPanel()`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanel.cs#L13) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public sealed class Inno.Editor.Core.EditorPanelAttribute : System.Attribute`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanelAttribute.cs#L9) | Registers an editor panel for automatic discovery. | — | — | -| [`public Inno.Editor.Core.EditorPanelAttribute.EditorPanelAttribute(string id, string title, int order = 0, bool defaultOpen = true, string menuPath = "", bool separatorBefore = false)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanelAttribute.cs#L36) | Creates a dockable panel registration with stable identity and presentation metadata.
`id`: The stable identity used for Panel-menu routing and reload-state retention.
`title`: The visible dockable-window title.
`order`: The stable panel and generated Panel-menu ordering value.
`defaultOpen`: Whether a newly discovered panel is visible before retained state is available.
`menuPath`: The optional slash-delimited category path under the generated Panel menu.
`separatorBefore`: Whether the generated toggle is preceded by a separator within its final menu category. | — | `System.ArgumentException`: Thrown when or is empty, or when contains an empty segment. | +| [`public Inno.Editor.Core.EditorPanelAttribute.EditorPanelAttribute(string id, string title, int order = 0, bool defaultOpen = true, string menuPath = "", bool separatorBefore = false)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanelAttribute.cs#L36) | Creates a dockable panel registration with stable identity and presentation metadata.
`id`: The stable identity used for Panel-menu routing and reload-state retention.
`title`: The visible dockable-window title.
`order`: The stable panel and generated Panel-menu ordering value.
`defaultOpen`: Whether a newly discovered panel is visible before retained state is available.
`menuPath`: The optional slash-delimited category path under the generated Panel menu.
`separatorBefore`: Whether the generated toggle is preceded by a separator within its final menu category. | — | `System.ArgumentException`: Thrown when id or title is empty, or when menuPath contains an empty segment. | | [`public string Inno.Editor.Core.EditorPanelAttribute.id { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanelAttribute.cs#L59) | Gets the stable panel identifier. | — | — | | [`public string Inno.Editor.Core.EditorPanelAttribute.title { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanelAttribute.cs#L64) | Gets the visible panel title. | — | — | | [`public int Inno.Editor.Core.EditorPanelAttribute.order { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanelAttribute.cs#L69) | Gets the stable panel ordering value. | — | — | @@ -480,92 +492,92 @@ Editor 模块更新与 Reload 事务使用 Edit Session;Play Tick 和运行对 | [`public string Inno.Editor.Core.EditorPanelAttribute.menuPath { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanelAttribute.cs#L79) | Gets the optional category path under the generated Panel menu. | — | — | | [`public bool Inno.Editor.Core.EditorPanelAttribute.separatorBefore { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorPanelAttribute.cs#L84) | Gets whether the generated panel toggle begins a new visual group. | — | — | | [`public static class Inno.Editor.Core.EditorTypeSpecificity`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorTypeSpecificity.cs#L7) | Ranks assignable editor extension targets by class ancestry, with interface registrations one step away. | — | — | -| [`public static bool Inno.Editor.Core.EditorTypeSpecificity.TryGet(System.Type concreteType, System.Type candidateType, out int distance)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorTypeSpecificity.cs#L27) | Determines whether a registration accepts a concrete target and returns its specificity distance.
`concreteType`: The target type supplied by the active extension generation.
`candidateType`: The registered class or interface accepted by the extension.
`distance`: Zero for an exact match, ancestry distance for classes, or one for an interface. | True when the registration accepts the target; otherwise false and the maximum distance. | `System.ArgumentNullException`: Either type is null. | +| [`public static bool Inno.Editor.Core.EditorTypeSpecificity.TryGet(System.Type concreteType, System.Type candidateType, out int distance)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorTypeSpecificity.cs#L27) | Determines whether a registration accepts a concrete target and returns its specificity distance.
`concreteType`: The target type supplied by the active extension generation.
`candidateType`: The registered class or interface accepted by the extension.
`distance`: Zero for an exact match, ancestry distance for classes, or one for an interface. | True when the registration accepts the target; otherwise false and the maximum distance. | `System.ArgumentNullException`: Either type is null. | | [`public interface Inno.Editor.Core.IEditorPanelReloadState`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/IEditorPanelReloadState.cs#L8) | Optionally migrates presentation-neutral panel state across assembly reloads. | — | — | | [`System.ReadOnlyMemory Inno.Editor.Core.IEditorPanelReloadState.CaptureReloadState()`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/IEditorPanelReloadState.cs#L16) | Captures presentation-neutral state without retaining runtime or plugin object references. | An immutable byte payload that can be consumed by the replacement panel generation. | — | -| [`void Inno.Editor.Core.IEditorPanelReloadState.RestoreReloadState(System.ReadOnlyMemory state)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/IEditorPanelReloadState.cs#L24) | Restores presentation-neutral state captured from the previous panel generation.
`state`: The immutable payload returned by the retiring panel generation. | — | — | +| [`void Inno.Editor.Core.IEditorPanelReloadState.RestoreReloadState(System.ReadOnlyMemory state)`](../../src/composition/editor/framework/Inno.Editor.Core/Extensions/IEditorPanelReloadState.cs#L24) | Restores presentation-neutral state captured from the previous panel generation.
`state`: The immutable payload returned by the retiring panel generation. | — | — | | [`public static class Inno.Editor.Core.EditorDisplayNames`](../../src/composition/editor/framework/Inno.Editor.Core/Presentation/EditorDisplayNames.cs#L9) | Formats readable Editor labels independently from a native UI context or session. | — | — | -| [`public static string Inno.Editor.Core.EditorDisplayNames.Nicify(string name)`](../../src/composition/editor/framework/Inno.Editor.Core/Presentation/EditorDisplayNames.cs#L20) | Converts an identifier into a readable editor label.
`name`: Source identifier. | A label with identifier separators and lower-to-upper transitions spaced; empty when the input is blank. | — | +| [`public static string Inno.Editor.Core.EditorDisplayNames.Nicify(string name)`](../../src/composition/editor/framework/Inno.Editor.Core/Presentation/EditorDisplayNames.cs#L20) | Converts an identifier into a readable editor label.
`name`: Source identifier. | A label with identifier separators and lower-to-upper transitions spaced; empty when the input is blank. | — | | [`public sealed class Inno.Editor.Core.EditorReloadCoordinator : Inno.Scripting.Reload.IScriptReloadCoordinator`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/EditorReloadCoordinator.cs#L16) | Coordinates weakly registered editor feature migrations around atomic assembly reload sessions. | — | — | -| [`public System.IDisposable Inno.Editor.Core.EditorReloadCoordinator.RegisterGuard(Inno.Editor.Core.IEditorReloadGuard guard)`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/EditorReloadCoordinator.cs#L34) | Registers a weak admission guard without stopping its owner or creating a generation transaction.
`guard`: The owner whose current state determines reload admission. | A caller-owned lease retaining the guard until registration is released. | `System.ArgumentNullException`: The guard is null. | -| [`public bool Inno.Editor.Core.EditorReloadCoordinator.CanRequestReload(out string? reason)`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/EditorReloadCoordinator.cs#L55) | Queries whether every registered owner accepts an explicit reload request.
`reason`: The first blocking reason, or null when the request is allowed. | True when all live guards permit a manual request. | — | -| [`public bool Inno.Editor.Core.EditorReloadCoordinator.CanActivateReload(out string? reason)`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/EditorReloadCoordinator.cs#L66) | Queries whether compilation and activation can proceed without interrupting a running session.
`reason`: The first blocking reason, or null when activation is allowed. | True when all live guards permit generation work. | — | -| [`public System.IDisposable Inno.Editor.Core.EditorReloadCoordinator.Register(Inno.Editor.Core.IEditorReloadParticipant participant)`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/EditorReloadCoordinator.cs#L81) | Registers an editor feature that owns generation-bound live state.
`participant`: The feature participant. The coordinator retains only a weak reference to this instance. | A registration lease that strongly retains the participant until the lease is disposed. The coordinator itself retains only a weak reference. | `System.ArgumentNullException`: Thrown when is . | -| [`public Inno.Extensibility.Reload.IAssemblyUnloadProbe Inno.Editor.Core.EditorReloadCoordinator.Execute(Inno.Extensibility.Modules.AssemblyReloadSession reload, Inno.Extensibility.Reload.IGenerationChange? externalChange = null)`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/EditorReloadCoordinator.cs#L113) | Applies one prepared assembly reload together with every registered editor feature migration.
`reload`: The prepared assembly reload session to activate and complete.
`externalChange`: Content recovery prepared before type publication, applied before Editor recovery, and restored before old values. | A monitor that observes cooperative unloading of assemblies retired by the committed reload. | `System.ArgumentNullException`: Thrown when is .
`System.AggregateException`: Thrown when activation fails and one or more feature or assembly rollback stages also fail. | +| [`public System.IDisposable Inno.Editor.Core.EditorReloadCoordinator.RegisterGuard(Inno.Editor.Core.IEditorReloadGuard guard)`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/EditorReloadCoordinator.cs#L34) | Registers a weak admission guard without stopping its owner or creating a generation transaction.
`guard`: The owner whose current state determines reload admission. | A caller-owned lease retaining the guard until registration is released. | `System.ArgumentNullException`: The guard is null. | +| [`public bool Inno.Editor.Core.EditorReloadCoordinator.CanRequestReload(out string? reason)`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/EditorReloadCoordinator.cs#L55) | Queries whether every registered owner accepts an explicit reload request.
`reason`: The first blocking reason, or null when the request is allowed. | True when all live guards permit a manual request. | — | +| [`public bool Inno.Editor.Core.EditorReloadCoordinator.CanActivateReload(out string? reason)`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/EditorReloadCoordinator.cs#L66) | Queries whether compilation and activation can proceed without interrupting a running session.
`reason`: The first blocking reason, or null when activation is allowed. | True when all live guards permit generation work. | — | +| [`public System.IDisposable Inno.Editor.Core.EditorReloadCoordinator.Register(Inno.Editor.Core.IEditorReloadParticipant participant)`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/EditorReloadCoordinator.cs#L81) | Registers an editor feature that owns generation-bound live state.
`participant`: The feature participant. The coordinator retains only a weak reference to this instance. | A registration lease that strongly retains the participant until the lease is disposed. The coordinator itself retains only a weak reference. | `System.ArgumentNullException`: Thrown when participant is null. | +| [`public Inno.Extensibility.Reload.IAssemblyUnloadProbe Inno.Editor.Core.EditorReloadCoordinator.Execute(Inno.Extensibility.Modules.AssemblyReloadSession reload, Inno.Extensibility.Reload.IGenerationChange? externalChange = null)`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/EditorReloadCoordinator.cs#L113) | Applies one prepared assembly reload together with every registered editor feature migration.
`reload`: The prepared assembly reload session to activate and complete.
`externalChange`: Content recovery prepared before type publication, applied before Editor recovery, and restored before old values. | A monitor that observes cooperative unloading of assemblies retired by the committed reload. | `System.ArgumentNullException`: Thrown when reload is null.
`System.AggregateException`: Thrown when activation fails and one or more feature or assembly rollback stages also fail. | | [`public void Inno.Editor.Core.EditorReloadCoordinator.RefreshDiagnostics()`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/EditorReloadCoordinator.cs#L128) | Requests every live participant to republish diagnostics derived from its current state. | — | — | -| [`public Inno.Editor.Core.EditorReloadCoordinator.EditorReloadCoordinator()`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/EditorReloadCoordinator.cs#L16) | Inherited or compiler-provided contract. | — | — | +| [`public Inno.Editor.Core.EditorReloadCoordinator.EditorReloadCoordinator()`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/EditorReloadCoordinator.cs#L16) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public interface Inno.Editor.Core.IEditorReloadGuard`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/IEditorReloadGuard.cs#L6) | Describes whether an editor owner has released the state required for a generation change. | — | — | | [`bool Inno.Editor.Core.IEditorReloadGuard.canRequestReload { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/IEditorReloadGuard.cs#L11) | Gets whether an explicit user reload request may be accepted in the current owner state. | — | — | | [`bool Inno.Editor.Core.IEditorReloadGuard.canActivateReload { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/IEditorReloadGuard.cs#L16) | Gets whether compilation and activation may proceed without a live isolated runtime session. | — | — | | [`string? Inno.Editor.Core.IEditorReloadGuard.blockingReason { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/IEditorReloadGuard.cs#L21) | Gets the reason admission is blocked, or null when the owner is ready for reload. | — | — | | [`public interface Inno.Editor.Core.IEditorReloadParticipant`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/IEditorReloadParticipant.cs#L10) | Contributes editor-owned live state to an assembly reload without coupling the reload requester to a feature domain. | — | — | -| [`Inno.Extensibility.Reload.IGenerationChange Inno.Editor.Core.IEditorReloadParticipant.Capture(Inno.Extensibility.Modules.AssemblyReloadContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/IEditorReloadParticipant.cs#L21) | Captures one isolated transaction for the prepared assembly generation.
`context`: The prepared assembly reload context containing previous and candidate participant state. | A transaction that has captured current state but has not modified live editor objects. | — | +| [`Inno.Extensibility.Reload.IGenerationChange Inno.Editor.Core.IEditorReloadParticipant.Capture(Inno.Extensibility.Modules.AssemblyReloadContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/IEditorReloadParticipant.cs#L21) | Captures one isolated transaction for the prepared assembly generation.
`context`: The prepared assembly reload context containing previous and candidate participant state. | A transaction that has captured current state but has not modified live editor objects. | — | | [`void Inno.Editor.Core.IEditorReloadParticipant.RefreshDiagnostics()`](../../src/composition/editor/framework/Inno.Editor.Core/Reloading/IEditorReloadParticipant.cs#L26) | Republishes diagnostics derived from the participant's current live state. | — | — | | [`public sealed class Inno.Editor.Core.EditorContext`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L13) | Provides passive project and frame state shared by editor extensions. Interaction routing is supplied separately by Inno.Editor.Interactions. | — | — | -| [`public Inno.Editor.Core.EditorContext.EditorContext(string projectDirectory, Inno.Editor.Core.EditorKeyboardPolicy keyboard)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L31) | Creates a passive editor context for one project.
`projectDirectory`: The project root containing Assets and Library.
`keyboard`: The explicit immutable conventions selected by product composition. | — | `System.ArgumentNullException`: The keyboard policy is null.
`System.ArgumentException`: Thrown when is empty. | -| [`public string Inno.Editor.Core.EditorContext.projectDirectory { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L47) | Gets the normalized project root directory. | — | — | -| [`public Inno.Editor.Core.EditorKeyboardPolicy Inno.Editor.Core.EditorContext.keyboard { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L52) | Gets the immutable keyboard conventions shared by discovery, dispatch and presentation. | — | — | -| [`public Inno.Editor.Core.EditorStatistics Inno.Editor.Core.EditorContext.statistics { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L57) | Gets the frame-scoped statistics exchange used by independent editor features and viewers. | — | — | -| [`public string Inno.Editor.Core.EditorContext.layoutPath { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L63) | Gets the absolute path of the project editor layout document. | — | — | -| [`public string Inno.Editor.Core.EditorContext.imguiLayout { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L69) | Gets the Dear ImGui layout text without editor module or panel state sections. | — | — | -| [`public System.Collections.Generic.IReadOnlyList Inno.Editor.Core.EditorContext.GetLayoutSectionNames(string prefix = "")`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L86) | Gets layout section names matching an ordinal prefix.
`prefix`: The prefix to match, or an empty string for every section. | A stable sorted snapshot of matching section names. | `System.ArgumentNullException`: Thrown when is . | -| [`public bool Inno.Editor.Core.EditorContext.TryGetLayoutSection(string sectionName, out System.Collections.Generic.IReadOnlyDictionary values)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L104) | Tries to read one independent editor layout section snapshot.
`sectionName`: The section name without its INI header syntax.
`values`: The copied values when the section exists. | when the requested section exists. | `System.ArgumentException`: Thrown when is empty or cannot be represented in the layout. | -| [`public void Inno.Editor.Core.EditorContext.SetLayoutSection(string sectionName, System.Collections.Generic.IEnumerable> values)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L126) | Adds or replaces one human-readable editor layout section in memory.
`sectionName`: The section name without its INI header syntax.
`values`: The complete scalar or JSON-formatted values. | — | `System.ArgumentNullException`: Thrown when is .
`System.ArgumentException`: Thrown when a section name, key, or value cannot be represented in the layout. | -| [`public bool Inno.Editor.Core.EditorContext.RemoveLayoutSection(string sectionName)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L145) | Removes one editor layout section from the in-memory document.
`sectionName`: The section name without its INI header syntax. | when an existing section was removed. | `System.ArgumentException`: Thrown when is empty or cannot be represented in the layout. | -| [`public void Inno.Editor.Core.EditorContext.SetImGuiLayout(string? value)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L154) | Replaces the Dear ImGui layout while retaining editor module and panel state sections.
`value`: The complete layout text returned by Dear ImGui. | — | — | -| [`public bool Inno.Editor.Core.EditorContext.SaveLayoutIfChanged()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L169) | Atomically saves the project editor layout when it changed. | when a changed document was written. | `System.IO.IOException`: Thrown when the layout document cannot be written atomically.
`System.UnauthorizedAccessException`: Thrown when the layout document is inaccessible. | -| [`public void Inno.Editor.Core.EditorContext.SaveLayout()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L181) | Atomically rewrites the complete project editor layout document. | — | `System.IO.IOException`: Thrown when the layout document cannot be written atomically.
`System.UnauthorizedAccessException`: Thrown when the layout document is inaccessible. | -| [`public Inno.Editor.Core.EditorFrame Inno.Editor.Core.EditorContext.frame { get; internal set; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L186) | Gets the latest immutable editor frame snapshot. | — | — | -| [`public bool Inno.Editor.Core.EditorContext.isFocused { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L191) | Gets whether any editor viewport currently owns application focus. | — | — | -| [`public readonly record struct Inno.Editor.Core.EditorFrame : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | Describes one immutable editor frame.
`deltaTime`: The elapsed frame time in seconds.
`totalTime`: The absolute editor runtime in seconds.
`isFocused`: Whether an editor viewport owns application focus. | — | — | -| [`public Inno.Editor.Core.EditorFrame.EditorFrame(float deltaTime, float totalTime, bool isFocused)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | Describes one immutable editor frame.
`deltaTime`: The elapsed frame time in seconds.
`totalTime`: The absolute editor runtime in seconds.
`isFocused`: Whether an editor viewport owns application focus. | — | — | +| [`public Inno.Editor.Core.EditorContext.EditorContext(string projectDirectory, Inno.Editor.Core.EditorKeyboardPolicy keyboard, string? initialLayoutDocument = null)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L41) | Creates a passive editor context for one project.
`projectDirectory`: The project root containing Assets and Library.
`keyboard`: The explicit immutable conventions selected by product composition.
`initialLayoutDocument`: An optional host-owned initial settings document, installed atomically only when editor.ini does not exist. Existing documents, including empty files, are preserved. | — | `System.ArgumentNullException`: The keyboard policy is null.
`System.ArgumentException`: Thrown when projectDirectory is empty.
`System.IO.IOException`: The current document cannot be read or its initial document cannot be installed.
`System.UnauthorizedAccessException`: The caller cannot access or initialize the project settings document. | +| [`public string Inno.Editor.Core.EditorContext.projectDirectory { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L58) | Gets the normalized project root directory. | — | — | +| [`public Inno.Editor.Core.EditorKeyboardPolicy Inno.Editor.Core.EditorContext.keyboard { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L63) | Gets the immutable keyboard conventions shared by discovery, dispatch and presentation. | — | — | +| [`public Inno.Editor.Core.EditorStatistics Inno.Editor.Core.EditorContext.statistics { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L68) | Gets the frame-scoped statistics exchange used by independent editor features and viewers. | — | — | +| [`public string Inno.Editor.Core.EditorContext.layoutPath { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L74) | Gets the absolute path of the project editor layout document. | — | — | +| [`public string Inno.Editor.Core.EditorContext.imguiLayout { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L80) | Gets the Dear ImGui layout text without editor module or panel state sections. | — | — | +| [`public System.Collections.Generic.IReadOnlyList Inno.Editor.Core.EditorContext.GetLayoutSectionNames(string prefix = "")`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L97) | Gets layout section names matching an ordinal prefix.
`prefix`: The prefix to match, or an empty string for every section. | A stable sorted snapshot of matching section names. | `System.ArgumentNullException`: Thrown when prefix is null. | +| [`public bool Inno.Editor.Core.EditorContext.TryGetLayoutSection(string sectionName, out System.Collections.Generic.IReadOnlyDictionary values)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L115) | Tries to read one independent editor layout section snapshot.
`sectionName`: The section name without its INI header syntax.
`values`: The copied values when the section exists. | true when the requested section exists. | `System.ArgumentException`: Thrown when sectionName is empty or cannot be represented in the layout. | +| [`public void Inno.Editor.Core.EditorContext.SetLayoutSection(string sectionName, System.Collections.Generic.IEnumerable> values)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L137) | Adds or replaces one human-readable editor layout section in memory.
`sectionName`: The section name without its INI header syntax.
`values`: The complete scalar or JSON-formatted values. | — | `System.ArgumentNullException`: Thrown when values is null.
`System.ArgumentException`: Thrown when a section name, key, or value cannot be represented in the layout. | +| [`public bool Inno.Editor.Core.EditorContext.RemoveLayoutSection(string sectionName)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L156) | Removes one editor layout section from the in-memory document.
`sectionName`: The section name without its INI header syntax. | true when an existing section was removed. | `System.ArgumentException`: Thrown when sectionName is empty or cannot be represented in the layout. | +| [`public void Inno.Editor.Core.EditorContext.SetImGuiLayout(string? value)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L165) | Replaces the Dear ImGui layout while retaining editor module and panel state sections.
`value`: The complete layout text returned by Dear ImGui. | — | — | +| [`public bool Inno.Editor.Core.EditorContext.SaveLayoutIfChanged()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L180) | Atomically saves the project editor layout when it changed. | true when a changed document was written. | `System.IO.IOException`: Thrown when the layout document cannot be written atomically.
`System.UnauthorizedAccessException`: Thrown when the layout document is inaccessible. | +| [`public void Inno.Editor.Core.EditorContext.SaveLayout()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L192) | Atomically rewrites the complete project editor layout document. | — | `System.IO.IOException`: Thrown when the layout document cannot be written atomically.
`System.UnauthorizedAccessException`: Thrown when the layout document is inaccessible. | +| [`public Inno.Editor.Core.EditorFrame Inno.Editor.Core.EditorContext.frame { get; internal set; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L197) | Gets the latest immutable editor frame snapshot. | — | — | +| [`public bool Inno.Editor.Core.EditorContext.isFocused { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorContext.cs#L202) | Gets whether any editor viewport currently owns application focus. | — | — | +| [`public readonly record struct Inno.Editor.Core.EditorFrame : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | Describes one immutable editor frame.
`deltaTime`: The elapsed frame time in seconds.
`totalTime`: The absolute editor runtime in seconds.
`isFocused`: Whether an editor viewport owns application focus. | — | — | +| [`public Inno.Editor.Core.EditorFrame.EditorFrame(float deltaTime, float totalTime, bool isFocused)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | Describes one immutable editor frame.
`deltaTime`: The elapsed frame time in seconds.
`totalTime`: The absolute editor runtime in seconds.
`isFocused`: Whether an editor viewport owns application focus. | — | — | | [`public float Inno.Editor.Core.EditorFrame.deltaTime { get; init; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L16) | The elapsed frame time in seconds. | — | — | | [`public float Inno.Editor.Core.EditorFrame.totalTime { get; init; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L17) | The absolute editor runtime in seconds. | — | — | | [`public bool Inno.Editor.Core.EditorFrame.isFocused { get; init; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L18) | Whether an editor viewport owns application focus. | — | — | | [`public override string Inno.Editor.Core.EditorFrame.ToString()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | -| [`public static bool Inno.Editor.Core.EditorFrame.operator !=(Inno.Editor.Core.EditorFrame left, Inno.Editor.Core.EditorFrame right)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.Core.EditorFrame.operator ==(Inno.Editor.Core.EditorFrame left, Inno.Editor.Core.EditorFrame right)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.Core.EditorFrame.operator !=(Inno.Editor.Core.EditorFrame left, Inno.Editor.Core.EditorFrame right)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Core.EditorFrame.operator ==(Inno.Editor.Core.EditorFrame left, Inno.Editor.Core.EditorFrame right)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.Core.EditorFrame.GetHashCode()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.Core.EditorFrame.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.Core.EditorFrame.Equals(Inno.Editor.Core.EditorFrame other)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | -| [`public void Inno.Editor.Core.EditorFrame.Deconstruct(out float deltaTime, out float totalTime, out bool isFocused)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | Inherited or compiler-provided contract. | — | — | +| [`public override bool Inno.Editor.Core.EditorFrame.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Core.EditorFrame.Equals(Inno.Editor.Core.EditorFrame other)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | +| [`public void Inno.Editor.Core.EditorFrame.Deconstruct(out float deltaTime, out float totalTime, out bool isFocused)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorFrame.cs#L15) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public sealed class Inno.Editor.Core.EditorKeyboardPolicy`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorKeyboardPolicy.cs#L9) | Supplies immutable keyboard conventions selected by the Editor product composition. | — | — | -| [`public Inno.Editor.Core.EditorKeyboardPolicy.EditorKeyboardPolicy(Inno.Core.Input.KeyModifier primaryModifier, string superModifierLabel)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorKeyboardPolicy.cs#L23) | Defines the primary shortcut modifier and the display name of the Super modifier.
`primaryModifier`: One Control, Super or Alt modifier used by symbolic primary shortcuts.
`superModifierLabel`: The nonempty product-specific name displayed for the Super modifier. | — | `System.ArgumentException`: The modifier is not one supported modifier or the label is empty. | +| [`public Inno.Editor.Core.EditorKeyboardPolicy.EditorKeyboardPolicy(Inno.Core.Input.KeyModifier primaryModifier, string superModifierLabel)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorKeyboardPolicy.cs#L23) | Defines the primary shortcut modifier and the display name of the Super modifier.
`primaryModifier`: One Control, Super or Alt modifier used by symbolic primary shortcuts.
`superModifierLabel`: The nonempty product-specific name displayed for the Super modifier. | — | `System.ArgumentException`: The modifier is not one supported modifier or the label is empty. | | [`public Inno.Core.Input.KeyModifier Inno.Editor.Core.EditorKeyboardPolicy.primaryModifier { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorKeyboardPolicy.cs#L37) | Gets the modifier used when resolving symbolic primary shortcuts. | — | — | | [`public string Inno.Editor.Core.EditorKeyboardPolicy.superModifierLabel { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorKeyboardPolicy.cs#L42) | Gets the product-selected display name of the Super modifier. | — | — | | [`public abstract class Inno.Editor.Core.EditorRuntime : System.IDisposable`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorRuntime.cs#L8) | Defines the presentation-independent lifecycle of an editor runtime. | — | — | -| [`protected Inno.Editor.Core.EditorRuntime.EditorRuntime(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorRuntime.cs#L19) | Creates a runtime for the supplied passive context.
`context`: The shared editor context. | — | `System.ArgumentNullException`: Thrown when is . | +| [`protected Inno.Editor.Core.EditorRuntime.EditorRuntime(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorRuntime.cs#L19) | Creates a runtime for the supplied passive context.
`context`: The shared editor context. | — | `System.ArgumentNullException`: Thrown when context is null. | | [`public Inno.Editor.Core.EditorContext Inno.Editor.Core.EditorRuntime.context { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorRuntime.cs#L27) | Gets the shared passive editor context. | — | — | | [`public abstract void Inno.Editor.Core.EditorRuntime.Start()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorRuntime.cs#L32) | Starts the runtime and activates its initial extension generation. | — | — | -| [`public abstract void Inno.Editor.Core.EditorRuntime.Update(Inno.Editor.Core.EditorFrame frame)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorRuntime.cs#L40) | Updates the runtime for one editor frame.
`frame`: The immutable frame state. | — | — | -| [`protected void Inno.Editor.Core.EditorRuntime.SetFrame(Inno.Editor.Core.EditorFrame frame)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorRuntime.cs#L48) | Advances frame-scoped data and publishes the latest immutable frame.
`frame`: The frame to publish. | — | — | +| [`public abstract void Inno.Editor.Core.EditorRuntime.Update(Inno.Editor.Core.EditorFrame frame)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorRuntime.cs#L40) | Updates the runtime for one editor frame.
`frame`: The immutable frame state. | — | — | +| [`protected void Inno.Editor.Core.EditorRuntime.SetFrame(Inno.Editor.Core.EditorFrame frame)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorRuntime.cs#L48) | Advances frame-scoped data and publishes the latest immutable frame.
`frame`: The frame to publish. | — | — | | [`public abstract void Inno.Editor.Core.EditorRuntime.Dispose()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorRuntime.cs#L57) | Stops the runtime and releases active extensions. | — | — | | [`public abstract class Inno.Editor.Core.EditorState`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorState.cs#L14) | Provides the serialization-neutral parameter used to capture or restore one editor extension's project state. | — | — | | [`protected Inno.Editor.Core.EditorState.EditorState()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorState.cs#L19) | Initializes the base contract for a runtime-owned editor state parameter. | — | — | -| [`public abstract T Inno.Editor.Core.EditorState.Get(string key, T fallback)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorState.cs#L42) | Reads a compatible value or returns the caller-provided fallback.
`key`: The stable key local to the owning module or panel.
`fallback`: The value returned when the key is absent, malformed, or incompatible with .
`T`: The neutral value type expected by the caller. | The stored compatible value, or . | `System.ArgumentException`: Thrown when is empty. | -| [`public abstract void Inno.Editor.Core.EditorState.Set(string key, T value)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorState.cs#L68) | Writes one neutral value under a stable extension-local key.
`key`: The stable key local to the owning module or panel.
`value`: The value to persist.
`T`: The neutral value type supplied by the caller. | — | `System.ArgumentException`: Thrown when is empty.
`System.InvalidOperationException`: Thrown when the state parameter was supplied for restoration and is therefore read-only.
`System.NotSupportedException`: Thrown when cannot be represented by the runtime state serializer. | +| [`public abstract T Inno.Editor.Core.EditorState.Get(string key, T fallback)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorState.cs#L42) | Reads a compatible value or returns the caller-provided fallback.
`T`: The neutral value type expected by the caller.
`key`: The stable key local to the owning module or panel.
`fallback`: The value returned when the key is absent, malformed, or incompatible with T. | The stored compatible value, or fallback. | `System.ArgumentException`: Thrown when key is empty. | +| [`public abstract void Inno.Editor.Core.EditorState.Set(string key, T value)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorState.cs#L68) | Writes one neutral value under a stable extension-local key.
`T`: The neutral value type supplied by the caller.
`key`: The stable key local to the owning module or panel.
`value`: The value to persist. | — | `System.ArgumentException`: Thrown when key is empty.
`System.InvalidOperationException`: Thrown when the state parameter was supplied for restoration and is therefore read-only.
`System.NotSupportedException`: Thrown when value cannot be represented by the runtime state serializer. | | [`public readonly record struct Inno.Editor.Core.EditorStatisticId : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L10) | Identifies one editor statistic across panels, modules, and reloadable extensions. | — | — | -| [`public Inno.Editor.Core.EditorStatisticId.EditorStatisticId(string value)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L21) | Creates a globally stable statistic identifier.
`value`: Non-empty globally stable identity. | — | `System.ArgumentException`: Thrown when is empty. | +| [`public Inno.Editor.Core.EditorStatisticId.EditorStatisticId(string value)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L21) | Creates a globally stable statistic identifier.
`value`: Non-empty globally stable identity. | — | `System.ArgumentException`: Thrown when value is empty. | | [`public string Inno.Editor.Core.EditorStatisticId.value { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L30) | Gets the globally stable identity. | — | — | | [`public bool Inno.Editor.Core.EditorStatisticId.isValid { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L35) | Gets whether this identifier contains a usable value. | — | — | | [`public override string Inno.Editor.Core.EditorStatisticId.ToString()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L43) | Formats this value as a human-readable representation. | The human-readable representation of this value. | — | -| [`public static bool Inno.Editor.Core.EditorStatisticId.operator !=(Inno.Editor.Core.EditorStatisticId left, Inno.Editor.Core.EditorStatisticId right)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L10) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.Core.EditorStatisticId.operator ==(Inno.Editor.Core.EditorStatisticId left, Inno.Editor.Core.EditorStatisticId right)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L10) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.Core.EditorStatisticId.operator !=(Inno.Editor.Core.EditorStatisticId left, Inno.Editor.Core.EditorStatisticId right)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L10) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Core.EditorStatisticId.operator ==(Inno.Editor.Core.EditorStatisticId left, Inno.Editor.Core.EditorStatisticId right)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L10) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.Core.EditorStatisticId.GetHashCode()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L10) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.Core.EditorStatisticId.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L10) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.Core.EditorStatisticId.Equals(Inno.Editor.Core.EditorStatisticId other)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L10) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | +| [`public override bool Inno.Editor.Core.EditorStatisticId.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L10) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Core.EditorStatisticId.Equals(Inno.Editor.Core.EditorStatisticId other)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L10) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | | [`public readonly record struct Inno.Editor.Core.EditorStatisticGroupId : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L49) | Identifies one visual group in the editor statistics presentation. | — | — | -| [`public Inno.Editor.Core.EditorStatisticGroupId.EditorStatisticGroupId(string value)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L60) | Creates a globally stable statistic-group identifier.
`value`: Non-empty globally stable identity. | — | `System.ArgumentException`: Thrown when is empty. | +| [`public Inno.Editor.Core.EditorStatisticGroupId.EditorStatisticGroupId(string value)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L60) | Creates a globally stable statistic-group identifier.
`value`: Non-empty globally stable identity. | — | `System.ArgumentException`: Thrown when value is empty. | | [`public string Inno.Editor.Core.EditorStatisticGroupId.value { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L69) | Gets the globally stable identity. | — | — | | [`public bool Inno.Editor.Core.EditorStatisticGroupId.isValid { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L74) | Gets whether this identifier contains a usable value. | — | — | | [`public override string Inno.Editor.Core.EditorStatisticGroupId.ToString()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L82) | Formats this value as a human-readable representation. | The human-readable representation of this value. | — | -| [`public static bool Inno.Editor.Core.EditorStatisticGroupId.operator !=(Inno.Editor.Core.EditorStatisticGroupId left, Inno.Editor.Core.EditorStatisticGroupId right)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L49) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.Core.EditorStatisticGroupId.operator ==(Inno.Editor.Core.EditorStatisticGroupId left, Inno.Editor.Core.EditorStatisticGroupId right)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L49) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.Core.EditorStatisticGroupId.operator !=(Inno.Editor.Core.EditorStatisticGroupId left, Inno.Editor.Core.EditorStatisticGroupId right)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L49) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Core.EditorStatisticGroupId.operator ==(Inno.Editor.Core.EditorStatisticGroupId left, Inno.Editor.Core.EditorStatisticGroupId right)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L49) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.Core.EditorStatisticGroupId.GetHashCode()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L49) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.Core.EditorStatisticGroupId.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L49) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.Core.EditorStatisticGroupId.Equals(Inno.Editor.Core.EditorStatisticGroupId other)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L49) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | +| [`public override bool Inno.Editor.Core.EditorStatisticGroupId.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L49) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Core.EditorStatisticGroupId.Equals(Inno.Editor.Core.EditorStatisticGroupId other)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L49) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | | [`public sealed class Inno.Editor.Core.EditorStatistic`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L88) | Describes one immutable, presentation-ready statistic without retaining provider instances or types. | — | — | -| [`public Inno.Editor.Core.EditorStatistic.EditorStatistic(Inno.Editor.Core.EditorStatisticId id, Inno.Editor.Core.EditorStatisticGroupId groupId, string groupName, string label, string value, int groupOrder = 0, int order = 0)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L117) | Creates one statistic contribution.
`id`: Globally stable statistic identity used for replacement within a frame.
`groupId`: Stable visual group identity.
`groupName`: User-facing group heading.
`label`: User-facing metric label.
`value`: Already formatted user-facing value.
`groupOrder`: Ascending group presentation order.
`order`: Ascending metric order within the group. | — | `System.ArgumentException`: Thrown when an identifier, group name, label, or value is empty. | +| [`public Inno.Editor.Core.EditorStatistic.EditorStatistic(Inno.Editor.Core.EditorStatisticId id, Inno.Editor.Core.EditorStatisticGroupId groupId, string groupName, string label, string value, int groupOrder = 0, int order = 0)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L117) | Creates one statistic contribution.
`id`: Globally stable statistic identity used for replacement within a frame.
`groupId`: Stable visual group identity.
`groupName`: User-facing group heading.
`label`: User-facing metric label.
`value`: Already formatted user-facing value.
`groupOrder`: Ascending group presentation order.
`order`: Ascending metric order within the group. | — | `System.ArgumentException`: Thrown when an identifier, group name, label, or value is empty. | | [`public Inno.Editor.Core.EditorStatisticId Inno.Editor.Core.EditorStatistic.id { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L145) | Gets the globally stable statistic identity. | — | — | | [`public Inno.Editor.Core.EditorStatisticGroupId Inno.Editor.Core.EditorStatistic.groupId { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L150) | Gets the stable visual group identity. | — | — | | [`public string Inno.Editor.Core.EditorStatistic.groupName { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L155) | Gets the user-facing group heading. | — | — | @@ -574,10 +586,10 @@ Editor 模块更新与 Reload 事务使用 Edit Session;Play Tick 和运行对 | [`public int Inno.Editor.Core.EditorStatistic.groupOrder { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L170) | Gets ascending group presentation order. | — | — | | [`public int Inno.Editor.Core.EditorStatistic.order { get; }`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L175) | Gets ascending metric order within the group. | — | — | | [`public sealed class Inno.Editor.Core.EditorStatistics`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L185) | Exchanges frame-scoped, reload-safe statistics between independent editor features and viewers. | — | — | -| [`public void Inno.Editor.Core.EditorStatistics.Publish(Inno.Editor.Core.EditorStatistic statistic)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L202) | Publishes or replaces one statistic for the current editor frame.
`statistic`: Immutable contribution containing no runtime provider references. | — | `System.ArgumentNullException`: Thrown when is . | -| [`public void Inno.Editor.Core.EditorStatistics.Publish(System.Collections.Generic.IEnumerable statistics)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L223) | Publishes or replaces several statistics for the current editor frame.
`statistics`: Contributions to publish in enumeration order. | — | `System.ArgumentNullException`: Thrown when or one of its values is null. | +| [`public void Inno.Editor.Core.EditorStatistics.Publish(Inno.Editor.Core.EditorStatistic statistic)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L202) | Publishes or replaces one statistic for the current editor frame.
`statistic`: Immutable contribution containing no runtime provider references. | — | `System.ArgumentNullException`: Thrown when statistic is null. | +| [`public void Inno.Editor.Core.EditorStatistics.Publish(System.Collections.Generic.IEnumerable statistics)`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L223) | Publishes or replaces several statistics for the current editor frame.
`statistics`: Contributions to publish in enumeration order. | — | `System.ArgumentNullException`: Thrown when statistics or one of its values is null. | | [`public System.Collections.Generic.IReadOnlyList Inno.Editor.Core.EditorStatistics.GetSnapshot()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L238) | Gets a deterministic snapshot combining current contributions with the previous completed frame for providers that draw after their consumer. | An immutable, sorted snapshot containing at most one value for each stable statistic ID. Unchanged content reuses the same snapshot; previously returned snapshots remain valid. | — | -| [`public Inno.Editor.Core.EditorStatistics.EditorStatistics()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L185) | Inherited or compiler-provided contract. | — | — | +| [`public Inno.Editor.Core.EditorStatistics.EditorStatistics()`](../../src/composition/editor/framework/Inno.Editor.Core/Runtime/EditorStatistics.cs#L185) | 由 C# 编译器生成的值契约成员。 | — | — | ## 项目依赖 diff --git a/docs/editor/Inno.Editor.Exporting.md b/docs/editor/Inno.Editor.Exporting.md index ed4a3391..4dcfb010 100644 --- a/docs/editor/Inno.Editor.Exporting.md +++ b/docs/editor/Inno.Editor.Exporting.md @@ -38,43 +38,75 @@ Editor/CLI 已完成这个协调;源码工作区中的 Project 用户不需要 EditorExportService 是无界面的导出 owner:StartGame/StartPlugin、Cancel、progress、错误和任务 drain 全部复用 Build pipeline 与 LifetimeScope。Workbench 拥有输入表单与阻塞 modal。服务不引用 ImGui、Panel 或 hosting;关闭时先取消并等待任务释放资源,不能让隐藏窗口丢弃活动导出。 +## 导出呈现快照 + +`EditorExportService.progress` 返回一份 owner-thread `EditorExportProgress`,包含当前操作身份、百分比、状态、错误、忙碌和取消请求。无可测量总量时 fraction 为 null,通用弹窗显示活动态;Support Pack 准备因此不再伪装成 0%。后台进度继续使用原有队列,但记录关联其所属操作;迟到记录和取消后的普通进度不会覆盖当前状态。呈现通过 `Cancel(operationId)` 请求取消,资源仍由现有导出事务退休。 + +Support Pack 细分阶段与工具活动由独立的 #57 处理,本页不将它描述为已经实现。 + ## 当前源码公开 API 清单 此清单对应当前 SDK 求值与源码符号;内部类型不构成公开 API。 + + + + + + + + + + + + + + + - - - + + - -| API 与源码 | 契约与参数 | 返回值 | 重要异常 | -| --- | --- | --- | --- | +| API | 职责与参数 | 返回语义 | 失败条件 | +|---|---|---|---| +| [`public readonly record struct Inno.Editor.Exporting.EditorExportProgress : System.IEquatable`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs#L24) | Contains one owner-thread export presentation snapshot.
`operationId`: The export identity within this service.
`fraction`: The last measured completion fraction, or null while the active phase has no measured total.
`status`: The actual stage or outcome message.
`error`: The current failure diagnostic, or empty.
`isBusy`: Whether work still owns resources.
`cancellationRequested`: Whether cancellation is draining work. | — | — | +| [`public Inno.Editor.Exporting.EditorExportProgress.EditorExportProgress(long operationId, float? fraction, string status, string error, bool isBusy, bool cancellationRequested)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs#L24) | Contains one owner-thread export presentation snapshot.
`operationId`: The export identity within this service.
`fraction`: The last measured completion fraction, or null while the active phase has no measured total.
`status`: The actual stage or outcome message.
`error`: The current failure diagnostic, or empty.
`isBusy`: Whether work still owns resources.
`cancellationRequested`: Whether cancellation is draining work. | — | — | +| [`public long Inno.Editor.Exporting.EditorExportProgress.operationId { get; init; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs#L25) | The export identity within this service. | — | — | +| [`public float? Inno.Editor.Exporting.EditorExportProgress.fraction { get; init; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs#L26) | The last measured completion fraction, or null while the active phase has no measured total. | — | — | +| [`public string Inno.Editor.Exporting.EditorExportProgress.status { get; init; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs#L27) | The actual stage or outcome message. | — | — | +| [`public string Inno.Editor.Exporting.EditorExportProgress.error { get; init; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs#L28) | The current failure diagnostic, or empty. | — | — | +| [`public bool Inno.Editor.Exporting.EditorExportProgress.isBusy { get; init; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs#L29) | Whether work still owns resources. | — | — | +| [`public bool Inno.Editor.Exporting.EditorExportProgress.cancellationRequested { get; init; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs#L30) | Whether cancellation is draining work. | — | — | +| [`public override string Inno.Editor.Exporting.EditorExportProgress.ToString()`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs#L24) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | +| [`public static bool Inno.Editor.Exporting.EditorExportProgress.operator !=(Inno.Editor.Exporting.EditorExportProgress left, Inno.Editor.Exporting.EditorExportProgress right)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs#L24) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Exporting.EditorExportProgress.operator ==(Inno.Editor.Exporting.EditorExportProgress left, Inno.Editor.Exporting.EditorExportProgress right)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs#L24) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public override int Inno.Editor.Exporting.EditorExportProgress.GetHashCode()`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs#L24) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | +| [`public override bool Inno.Editor.Exporting.EditorExportProgress.Equals(object obj)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs#L24) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Exporting.EditorExportProgress.Equals(Inno.Editor.Exporting.EditorExportProgress other)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs#L24) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | +| [`public void Inno.Editor.Exporting.EditorExportProgress.Deconstruct(out long operationId, out float? fraction, out string status, out string error, out bool isBusy, out bool cancellationRequested)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs#L24) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public sealed class Inno.Editor.Exporting.EditorExportService : Inno.Editor.Core.EditorModule`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L20) | Owns asynchronous export, progress, cancellation and retirement independently from presentation. | — | — | -| [`public bool Inno.Editor.Exporting.EditorExportService.isPluginBusy { get; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L42) | Gets whether a Plugin source export still owns build resources. | — | — | -| [`public bool Inno.Editor.Exporting.EditorExportService.isGameBusy { get; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L46) | Gets whether a game export or its Support Pack preparation is active. | — | — | -| [`public string Inno.Editor.Exporting.EditorExportService.status { get; private set; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L50) | Gets the latest owner-thread progress message. | — | — | -| [`public string Inno.Editor.Exporting.EditorExportService.error { get; private set; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L54) | Gets the last failure or cancellation diagnostic, or an empty string. | — | — | -| [`public float Inno.Editor.Exporting.EditorExportService.gameProgress { get; private set; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L58) | Gets monotonic progress for the current game build, from zero through one. | — | — | -| [`public System.Collections.Generic.IReadOnlyList Inno.Editor.Exporting.EditorExportService.availableGameTargets { get; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L62) | Gets the targets registered by the active Build distribution. | — | — | -| [`public System.Collections.Generic.IReadOnlyList Inno.Editor.Exporting.EditorExportService.GetManagedDeployments(Inno.Build.BuildTargetId target)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L73) | Gets deployment implementations registered for a target.
`target`: The explicitly chosen build target. | The registered deployment choices; no host fallback is introduced. | — | -| [`public string Inno.Editor.Exporting.EditorExportService.GetGameTargetDisplayName(Inno.Build.BuildTargetId target)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L83) | Gets a registered target label or a diagnostic for an unavailable target.
`target`: The target to describe. | A presentation label; never used as a routing identity. | — | -| [`public void Inno.Editor.Exporting.EditorExportService.StartPlugin(Inno.Build.PluginBuildRequest request)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L96) | Starts a source-package export using the existing Build pipeline.
`request`: The complete, explicitly selected package request. | — | `System.InvalidOperationException`: Another export still owns the service. | -| [`public void Inno.Editor.Exporting.EditorExportService.StartGame(Inno.Build.GameBuildRequest request)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L115) | Prepares the selected Support Pack before capturing and building the game.
`request`: The complete game request; no form or window state is retained. | — | `System.InvalidOperationException`: Another export still owns the service. | -| [`public void Inno.Editor.Exporting.EditorExportService.Cancel()`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L137) | Requests cancellation without releasing resources before their owned work drains. | — | — | -| [`protected override void Inno.Editor.Exporting.EditorExportService.OnUpdate(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L157) | Advances compilation tickets, build progress, and completed export tasks.
`context`: The active Editor context for the current frame. | — | — | -| [`protected override void Inno.Editor.Exporting.EditorExportService.OnStop(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L177) | Cancels and drains active export work before the Editor generation is stopped.
`context`: The active Editor context being stopped. | — | — | -| [`protected override void Inno.Editor.Exporting.EditorExportService.OnDispose()`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L185) | Drains export cleanup before releasing cancellation resources owned by this module. | — | — | +| [`public bool Inno.Editor.Exporting.EditorExportService.isPluginBusy { get; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L46) | Gets whether a Plugin source export still owns build resources. | — | — | +| [`public bool Inno.Editor.Exporting.EditorExportService.isGameBusy { get; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L50) | Gets whether a game export or its Support Pack preparation is active. | — | — | +| [`public Inno.Editor.Exporting.EditorExportProgress Inno.Editor.Exporting.EditorExportService.progress { get; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L54) | Gets one owner-thread snapshot for the current export, including cancellation and action identity. | — | — | +| [`public void Inno.Editor.Exporting.EditorExportService.Cancel(long operationId)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L63) | Cancels the observed export only while that operation still owns this service.
`operationId`: The operation observed by the caller. | — | — | +| [`public System.Collections.Generic.IReadOnlyList Inno.Editor.Exporting.EditorExportService.availableGameTargets { get; }`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L72) | Gets the targets registered by the active Build distribution. | — | — | +| [`public System.Collections.Generic.IReadOnlyList Inno.Editor.Exporting.EditorExportService.GetManagedDeployments(Inno.Build.BuildTargetId target)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L83) | Gets deployment implementations registered for a target.
`target`: The explicitly chosen build target. | The registered deployment choices; no host fallback is introduced. | — | +| [`public string Inno.Editor.Exporting.EditorExportService.GetGameTargetDisplayName(Inno.Build.BuildTargetId target)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L93) | Gets a registered target label or a diagnostic for an unavailable target.
`target`: The target to describe. | A presentation label; never used as a routing identity. | — | +| [`public void Inno.Editor.Exporting.EditorExportService.StartPlugin(Inno.Build.PluginBuildRequest request)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L106) | Starts a source-package export using the existing Build pipeline.
`request`: The complete, explicitly selected package request. | — | `System.InvalidOperationException`: Another export still owns the service. | +| [`public void Inno.Editor.Exporting.EditorExportService.StartGame(Inno.Build.GameBuildRequest request)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L125) | Prepares the selected Support Pack before capturing and building the game.
`request`: The complete game request; no form or window state is retained. | — | `System.InvalidOperationException`: Another export still owns the service. | +| [`protected override void Inno.Editor.Exporting.EditorExportService.OnUpdate(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L167) | Advances compilation tickets, build progress, and completed export tasks.
`context`: The active Editor context for the current frame. | — | — | +| [`protected override void Inno.Editor.Exporting.EditorExportService.OnStop(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L190) | Cancels and drains active export work before the Editor generation is stopped.
`context`: The active Editor context being stopped. | — | — | +| [`protected override void Inno.Editor.Exporting.EditorExportService.OnDispose()`](../../src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs#L198) | Drains export cleanup before releasing cancellation resources owned by this module. | — | — | ## 项目依赖 diff --git a/docs/editor/Inno.Editor.ImGui.md b/docs/editor/Inno.Editor.ImGui.md index 286fa28a..756be1d8 100644 --- a/docs/editor/Inno.Editor.ImGui.md +++ b/docs/editor/Inno.Editor.ImGui.md @@ -231,6 +231,43 @@ static void DrawHelp() } ``` +## 动态消息与进度弹窗 + +`MeasureDialog` 与 `DrawDialog` 复用同一份 `DialogPresentation`。presentation 只含文本、可选进度、详情和动作策略;`DialogLayout` 只公开所需 `size`,其余布局计算属于 Widget 内部。Renderer 不认识脚本、导出、Sample 或具体平台。 + +正文很长时只有一个滚动 Child;Modal 拥有外层 padding,正文不重复增加 inset。进度和操作行留在正文之外,尺寸、换行宽度、字体和动作状态来自同一帧。未知总量通过 indeterminate 显示活动,不生成虚假百分比。测量在 Session 内最多复用两份结果,每份文本总量不超过 16,384 字符;键覆盖可用区域、实际字体与烘焙身份、字形/源变化、尺度及布局值。缓存只保留中立值,Session 退休时清除;共享或 remapped 字体按请求重新测量,不延长原生字体借用。Escape 只有在调用方明确开启 `cancelOnEscape` 时才触发动作,不能把任意按钮隐式视为 Cancel。 + +以下示例通过当前逻辑 API 实现一个可关闭消息窗口: + +```csharp +using System.Numerics; +using InnoEditor.Core; +using InnoEditor.ImGui; + +[EditorModal("example.message", "Message")] +public sealed class MessageModal : EditorModal +{ + private bool m_visible = true; + private DialogPresentation m_content; + private DialogLayout m_layout; + public override bool isVisible => m_visible; + public override bool allowScrolling => false; + protected override Vector2? OnPrepare( + EditorContext context, + Vector2 availableContentSize + ) { + m_content = new("A message that can wrap.", actionLabel: "Close", cancelOnEscape: true); + m_layout = EditorUiSession.current.widgets.MeasureDialog(m_content, availableContentSize); + return m_layout.size; + } + protected override void OnDraw(EditorContext context) + { + if (EditorUiSession.current.widgets.DrawDialog(m_content, m_layout)) + m_visible = false; + } +} +``` + ## 当前源码公开 API 清单 此清单对应当前 SDK 求值与源码符号;内部类型不构成公开 API。 @@ -360,6 +397,7 @@ static void DrawHelp() + @@ -1205,7 +1243,6 @@ static void DrawHelp() - @@ -1300,6 +1337,8 @@ static void DrawHelp() + + @@ -1362,6 +1401,7 @@ static void DrawHelp() + @@ -1372,6 +1412,24 @@ static void DrawHelp() + + + + + + + + + + + + + + + + + + @@ -1456,39 +1514,39 @@ static void DrawHelp() -| API 与源码 | 契约与参数 | 返回值 | 重要异常 | -| --- | --- | --- | --- | +| API | 职责与参数 | 返回语义 | 失败条件 | +|---|---|---|---| | [`public static class Inno.Editor.ImGui.ImGui`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Controls.cs#L9) | Provides pointer-free controls within the active Editor UI session. | — | — | -| [`public static bool Inno.Editor.ImGui.ImGui.InvisibleButton(string label, System.Numerics.Vector2 size, Inno.Editor.ImGui.ImGuiButtonFlags flags = Inno.Editor.ImGui.ImGuiButtonFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Controls.cs#L26) | Submits an explicitly drawn control interaction rectangle.
`label`: The visible label and optional stable ID suffix.
`size`: The explicit two-dimensional extent.
`flags`: The explicit control and interaction options. | True when the documented control event or condition is present; otherwise false. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.MenuItem(string label, string shortcut = "", bool selected = false, bool enabled = true)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Controls.cs#L53) | Draws a menu item with explicit availability and checked state.
`label`: The visible label and optional stable ID suffix.
`shortcut`: A display label only; execution remains with the Action router.
`selected`: Whether the item is currently selected.
`enabled`: Whether the control can accept input. | True when the documented control event or condition is present; otherwise false. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.SliderInt(string label, ref int value, int minimum, int maximum, string format = "%d", Inno.Editor.ImGui.ImGuiSliderFlags flags = Inno.Editor.ImGui.ImGuiSliderFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Controls.cs#L87) | Edits an integer within explicit inclusive bounds.
`label`: The visible label and optional stable ID suffix.
`value`: The caller-owned value updated only after an accepted edit.
`minimum`: The inclusive lower bound or upper-left corner.
`maximum`: The inclusive upper bound or lower-right corner.
`format`: The numeric display format.
`flags`: The explicit control and interaction options. | True when the documented control event or condition is present; otherwise false. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.DragInt(string label, ref int value, float speed = 1, int minimum = 0, int maximum = 0, string format = "%d", Inno.Editor.ImGui.ImGuiSliderFlags flags = Inno.Editor.ImGui.ImGuiSliderFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Controls.cs#L126) | Edits an integer by pointer drag with explicit speed and optional bounds.
`label`: The visible label and optional stable ID suffix.
`value`: The caller-owned value updated only after an accepted edit.
`speed`: The pointer movement multiplier.
`minimum`: The inclusive lower bound or upper-left corner.
`maximum`: The inclusive upper bound or lower-right corner.
`format`: The numeric display format.
`flags`: The explicit control and interaction options. | True when the documented control event or condition is present; otherwise false. | — | -| [`public static uint Inno.Editor.ImGui.ImGui.GetStyleColor(Inno.Editor.ImGui.ImGuiCol color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Drawing.cs#L20) | Gets the current style color including the active alpha.
`color`: The packed RGBA color or semantic style slot. | A copied value from the active presentation context. | — | -| [`public static uint Inno.Editor.ImGui.ImGui.GetControlId(string label)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Drawing.cs#L35) | Derives a control identity from the current window and ID stack.
`label`: The visible label and optional stable ID suffix. | A copied value from the active presentation context. | — | -| [`public static void Inno.Editor.ImGui.ImGui.PushClipRect(System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, bool intersect)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Drawing.cs#L53) | Clips subsequent controls and drawing to a screen rectangle.
`minimum`: The inclusive lower bound or upper-left corner.
`maximum`: The inclusive upper bound or lower-right corner.
`intersect`: Whether to intersect the enclosing clip. | — | — | +| [`public static bool Inno.Editor.ImGui.ImGui.InvisibleButton(string label, System.Numerics.Vector2 size, Inno.Editor.ImGui.ImGuiButtonFlags flags = Inno.Editor.ImGui.ImGuiButtonFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Controls.cs#L26) | Submits an explicitly drawn control interaction rectangle.
`label`: The visible label and optional stable ID suffix.
`size`: The explicit two-dimensional extent.
`flags`: The explicit control and interaction options. | True when the documented control event or condition is present; otherwise false. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.MenuItem(string label, string shortcut = "", bool selected = false, bool enabled = true)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Controls.cs#L53) | Draws a menu item with explicit availability and checked state.
`label`: The visible label and optional stable ID suffix.
`shortcut`: A display label only; execution remains with the Action router.
`selected`: Whether the item is currently selected.
`enabled`: Whether the control can accept input. | True when the documented control event or condition is present; otherwise false. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.SliderInt(string label, ref int value, int minimum, int maximum, string format = "%d", Inno.Editor.ImGui.ImGuiSliderFlags flags = Inno.Editor.ImGui.ImGuiSliderFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Controls.cs#L87) | Edits an integer within explicit inclusive bounds.
`label`: The visible label and optional stable ID suffix.
`value`: The caller-owned value updated only after an accepted edit.
`minimum`: The inclusive lower bound or upper-left corner.
`maximum`: The inclusive upper bound or lower-right corner.
`format`: The numeric display format.
`flags`: The explicit control and interaction options. | True when the documented control event or condition is present; otherwise false. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.DragInt(string label, ref int value, float speed = 1, int minimum = 0, int maximum = 0, string format = "%d", Inno.Editor.ImGui.ImGuiSliderFlags flags = Inno.Editor.ImGui.ImGuiSliderFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Controls.cs#L126) | Edits an integer by pointer drag with explicit speed and optional bounds.
`label`: The visible label and optional stable ID suffix.
`value`: The caller-owned value updated only after an accepted edit.
`speed`: The pointer movement multiplier.
`minimum`: The inclusive lower bound or upper-left corner.
`maximum`: The inclusive upper bound or lower-right corner.
`format`: The numeric display format.
`flags`: The explicit control and interaction options. | True when the documented control event or condition is present; otherwise false. | — | +| [`public static uint Inno.Editor.ImGui.ImGui.GetStyleColor(Inno.Editor.ImGui.ImGuiCol color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Drawing.cs#L20) | Gets the current style color including the active alpha.
`color`: The packed RGBA color or semantic style slot. | A copied value from the active presentation context. | — | +| [`public static uint Inno.Editor.ImGui.ImGui.GetControlId(string label)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Drawing.cs#L35) | Derives a control identity from the current window and ID stack.
`label`: The visible label and optional stable ID suffix. | A copied value from the active presentation context. | — | +| [`public static void Inno.Editor.ImGui.ImGui.PushClipRect(System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, bool intersect)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Drawing.cs#L53) | Clips subsequent controls and drawing to a screen rectangle.
`minimum`: The inclusive lower bound or upper-left corner.
`maximum`: The inclusive upper bound or lower-right corner.
`intersect`: Whether to intersect the enclosing clip. | — | — | | [`public static void Inno.Editor.ImGui.ImGui.PopClipRect()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Drawing.cs#L65) | Restores the enclosing control clip after a matching push. | — | — | | [`public static System.Numerics.Vector2 Inno.Editor.ImGui.ImGui.GetMousePos()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L17) | Gets the current pointer position in screen-space UI units. | A copied value from the active presentation context. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.IsMouseClicked(Inno.Editor.ImGui.ImGuiMouseButton button, bool repeat = false)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L35) | Checks a pointer-button press in the current frame.
`button`: The pointer button to inspect.
`repeat`: Whether a held key or button may produce repeats. | True when the documented control event or condition is present; otherwise false. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.IsMouseReleased(Inno.Editor.ImGui.ImGuiMouseButton button)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L52) | Checks a pointer-button release in the current frame.
`button`: The pointer button to inspect. | True when the documented control event or condition is present; otherwise false. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.IsMouseDoubleClicked(Inno.Editor.ImGui.ImGuiMouseButton button)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L67) | Checks the backend-classified double-click event.
`button`: The pointer button to inspect. | True when the documented control event or condition is present; otherwise false. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.IsKeyDown(Inno.Editor.ImGui.ImGuiKey key)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L82) | Checks whether a presentation key remains held.
`key`: The presentation key to inspect. | True when the documented control event or condition is present; otherwise false. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.IsKeyPressed(Inno.Editor.ImGui.ImGuiKey key, bool repeat = true)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L100) | Checks a presentation-key press with explicit repeat policy.
`key`: The presentation key to inspect.
`repeat`: Whether a held key or button may produce repeats. | True when the documented control event or condition is present; otherwise false. | — | -| [`public static void Inno.Editor.ImGui.ImGui.ResetMouseDragDelta(Inno.Editor.ImGui.ImGuiMouseButton button)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L114) | Resets the consumed pointer-drag distance.
`button`: The pointer button to inspect. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.SetMouseCursor(Inno.Editor.ImGui.ImGuiMouseCursor cursor)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L126) | Requests the semantic cursor for the hovered control.
`cursor`: The semantic pointer shape. | — | — | -| [`public static bool Inno.Editor.ImGui.ImGui.IsMouseHoveringRect(System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, bool clip = true)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L147) | Checks pointer containment in a screen rectangle with optional window clipping.
`minimum`: The inclusive lower bound or upper-left corner.
`maximum`: The inclusive upper bound or lower-right corner.
`clip`: Whether the current clipping rectangle participates. | True when the documented control event or condition is present; otherwise false. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.IsWindowHovered(Inno.Editor.ImGui.ImGuiHoveredFlags flags = Inno.Editor.ImGui.ImGuiHoveredFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L165) | Checks window hover under the declared interaction policy.
`flags`: The explicit control and interaction options. | True when the documented control event or condition is present; otherwise false. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.IsWindowFocused(Inno.Editor.ImGui.ImGuiFocusedFlags flags = Inno.Editor.ImGui.ImGuiFocusedFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L180) | Checks keyboard focus within the declared window scope.
`flags`: The explicit control and interaction options. | True when the documented control event or condition is present; otherwise false. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.IsMouseClicked(Inno.Editor.ImGui.ImGuiMouseButton button, bool repeat = false)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L35) | Checks a pointer-button press in the current frame.
`button`: The pointer button to inspect.
`repeat`: Whether a held key or button may produce repeats. | True when the documented control event or condition is present; otherwise false. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.IsMouseReleased(Inno.Editor.ImGui.ImGuiMouseButton button)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L52) | Checks a pointer-button release in the current frame.
`button`: The pointer button to inspect. | True when the documented control event or condition is present; otherwise false. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.IsMouseDoubleClicked(Inno.Editor.ImGui.ImGuiMouseButton button)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L67) | Checks the backend-classified double-click event.
`button`: The pointer button to inspect. | True when the documented control event or condition is present; otherwise false. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.IsKeyDown(Inno.Editor.ImGui.ImGuiKey key)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L82) | Checks whether a presentation key remains held.
`key`: The presentation key to inspect. | True when the documented control event or condition is present; otherwise false. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.IsKeyPressed(Inno.Editor.ImGui.ImGuiKey key, bool repeat = true)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L100) | Checks a presentation-key press with explicit repeat policy.
`key`: The presentation key to inspect.
`repeat`: Whether a held key or button may produce repeats. | True when the documented control event or condition is present; otherwise false. | — | +| [`public static void Inno.Editor.ImGui.ImGui.ResetMouseDragDelta(Inno.Editor.ImGui.ImGuiMouseButton button)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L114) | Resets the consumed pointer-drag distance.
`button`: The pointer button to inspect. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.SetMouseCursor(Inno.Editor.ImGui.ImGuiMouseCursor cursor)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L126) | Requests the semantic cursor for the hovered control.
`cursor`: The semantic pointer shape. | — | — | +| [`public static bool Inno.Editor.ImGui.ImGui.IsMouseHoveringRect(System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, bool clip = true)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L147) | Checks pointer containment in a screen rectangle with optional window clipping.
`minimum`: The inclusive lower bound or upper-left corner.
`maximum`: The inclusive upper bound or lower-right corner.
`clip`: Whether the current clipping rectangle participates. | True when the documented control event or condition is present; otherwise false. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.IsWindowHovered(Inno.Editor.ImGui.ImGuiHoveredFlags flags = Inno.Editor.ImGui.ImGuiHoveredFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L165) | Checks window hover under the declared interaction policy.
`flags`: The explicit control and interaction options. | True when the documented control event or condition is present; otherwise false. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.IsWindowFocused(Inno.Editor.ImGui.ImGuiFocusedFlags flags = Inno.Editor.ImGui.ImGuiFocusedFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L180) | Checks keyboard focus within the declared window scope.
`flags`: The explicit control and interaction options. | True when the documented control event or condition is present; otherwise false. | — | | [`public static bool Inno.Editor.ImGui.ImGui.IsAnyItemHovered()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L192) | Checks whether a submitted control currently owns hover. | True when the documented control event or condition is present; otherwise false. | — | | [`public static bool Inno.Editor.ImGui.ImGui.IsAnyItemActive()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L204) | Checks whether a submitted control owns an active interaction. | True when the documented control event or condition is present; otherwise false. | — | | [`public static bool Inno.Editor.ImGui.ImGui.IsItemActivated()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L216) | Checks the first frame of the last control interaction. | True when the documented control event or condition is present; otherwise false. | — | | [`public static bool Inno.Editor.ImGui.ImGui.IsItemDeactivatedAfterEdit()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L228) | Checks the completion frame of an edited control. | True when the documented control event or condition is present; otherwise false. | — | -| [`public static void Inno.Editor.ImGui.ImGui.SetKeyboardFocusHere(int offset = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L240) | Requests focus for a relative control position.
`offset`: The relative focus offset from the next submitted control. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.SetKeyboardFocusHere(int offset = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L240) | Requests focus for a relative control position.
`offset`: The relative focus offset from the next submitted control. | — | — | | [`public static void Inno.Editor.ImGui.ImGui.SetItemDefaultFocus()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L249) | Chooses the last item as the default selection in an appearing popup. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.SetClipboardText(string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L261) | Copies literal text through the host clipboard adapter.
`text`: Literal text; no formatting interpretation is applied. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.SetClipboardText(string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L261) | Copies literal text through the host clipboard adapter.
`text`: Literal text; no formatting interpretation is applied. | — | — | | [`public static int Inno.Editor.ImGui.ImGui.GetFrameCount()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Input.cs#L273) | Gets the current native frame identity for transient diagnostics. | A copied value from the active presentation context. | — | -| [`public static void Inno.Editor.ImGui.ImGui.SetCursorScreenPosition(System.Numerics.Vector2 position)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L17) | Places the next control at a screen-space location.
`position`: The requested coordinate in UI units. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.SetCursorPosX(float position)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L29) | Changes only the local horizontal layout cursor.
`position`: The requested coordinate in UI units. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.SetCursorPosY(float position)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L41) | Changes only the local vertical layout cursor.
`position`: The requested coordinate in UI units. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.SetCursorScreenPosition(System.Numerics.Vector2 position)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L17) | Places the next control at a screen-space location.
`position`: The requested coordinate in UI units. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.SetCursorPosX(float position)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L29) | Changes only the local horizontal layout cursor.
`position`: The requested coordinate in UI units. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.SetCursorPosY(float position)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L41) | Changes only the local vertical layout cursor.
`position`: The requested coordinate in UI units. | — | — | | [`public static float Inno.Editor.ImGui.ImGui.GetCursorPosX()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L53) | Gets the local horizontal layout cursor. | A copied value from the active presentation context. | — | | [`public static float Inno.Editor.ImGui.ImGui.GetCursorPosY()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L65) | Gets the local vertical layout cursor. | A copied value from the active presentation context. | — | | [`public static System.Numerics.Vector2 Inno.Editor.ImGui.ImGui.GetWindowPos()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L77) | Gets the current window screen-space origin. | A copied value from the active presentation context. | — | @@ -1500,100 +1558,101 @@ static void DrawHelp() | [`public static float Inno.Editor.ImGui.ImGui.GetWindowDpiScale()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L149) | Gets the native viewport scale for the current window. | A copied value from the active presentation context. | — | | [`public static void Inno.Editor.ImGui.ImGui.AlignTextToFramePadding()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L158) | Aligns the next text baseline with framed controls. | — | — | | [`public static void Inno.Editor.ImGui.ImGui.SetNextItemAllowOverlap()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L167) | Allows explicitly layered controls to share the next item bounds. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.SetNextWindowSize(System.Numerics.Vector2 size, Inno.Editor.ImGui.ImGuiCond condition = Inno.Editor.ImGui.ImGuiCond.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L182) | Requests a size for the next window under an explicit layout condition.
`size`: The explicit two-dimensional extent.
`condition`: The condition controlling when the request is applied. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.SetNextWindowContentSize(System.Numerics.Vector2 size)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L196) | Declares virtual content size for the next scrollable window.
`size`: The explicit two-dimensional extent. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.Indent(float amount = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L208) | Indents subsequent controls by an explicit amount or the standard step.
`amount`: The requested layout distance. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.Unindent(float amount = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L220) | Restores a matching indentation step.
`amount`: The requested layout distance. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.PushTextWrapPos(float position = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L232) | Restricts subsequent text wrapping to a local horizontal boundary.
`position`: The requested coordinate in UI units. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.SetNextWindowSize(System.Numerics.Vector2 size, Inno.Editor.ImGui.ImGuiCond condition = Inno.Editor.ImGui.ImGuiCond.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L182) | Requests a size for the next window under an explicit layout condition.
`size`: The explicit two-dimensional extent.
`condition`: The condition controlling when the request is applied. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.SetNextWindowContentSize(System.Numerics.Vector2 size)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L196) | Declares virtual content size for the next scrollable window.
`size`: The explicit two-dimensional extent. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.Indent(float amount = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L208) | Indents subsequent controls by an explicit amount or the standard step.
`amount`: The requested layout distance. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.Unindent(float amount = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L220) | Restores a matching indentation step.
`amount`: The requested layout distance. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.PushTextWrapPos(float position = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L232) | Restricts subsequent text wrapping to a local horizontal boundary.
`position`: The requested coordinate in UI units. | — | — | | [`public static void Inno.Editor.ImGui.ImGui.PopTextWrapPos()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L241) | Restores the enclosing text-wrap boundary. | — | — | | [`public static float Inno.Editor.ImGui.ImGui.GetScrollY()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L253) | Gets the current vertical scroll position. | A copied value from the active presentation context. | — | | [`public static float Inno.Editor.ImGui.ImGui.GetScrollMaxY()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L265) | Gets the current vertical scroll range. | A copied value from the active presentation context. | — | -| [`public static void Inno.Editor.ImGui.ImGui.SetScrollHereY(float ratio = 0.5)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L277) | Scrolls the most recently submitted control into the requested relative position.
`ratio`: The relative alignment from zero through one. | — | — | -| [`public static bool Inno.Editor.ImGui.ImGui.TableSetColumnIndex(int index)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Tables.cs#L20) | Selects a declared table column for subsequent controls.
`index`: The zero-based item index. | True when the documented control event or condition is present; otherwise false. | — | -| [`public static void Inno.Editor.ImGui.ImGui.TableSetBgColor(Inno.Editor.ImGui.ImGuiTableBgTarget target, uint color, int column = -1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Tables.cs#L38) | Sets a table row or cell background through the current table scope.
`target`: The table background role.
`color`: The packed RGBA color or semantic style slot.
`column`: The target column, or -1 for the current row. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.SetScrollHereY(float ratio = 0.5)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Layout.cs#L277) | Scrolls the most recently submitted control into the requested relative position.
`ratio`: The relative alignment from zero through one. | — | — | +| [`public static bool Inno.Editor.ImGui.ImGui.TableSetColumnIndex(int index)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Tables.cs#L20) | Selects a declared table column for subsequent controls.
`index`: The zero-based item index. | True when the documented control event or condition is present; otherwise false. | — | +| [`public static void Inno.Editor.ImGui.ImGui.TableSetBgColor(Inno.Editor.ImGui.ImGuiTableBgTarget target, uint color, int column = -1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/ImGui.Tables.cs#L38) | Sets a table row or cell background through the current table scope.
`target`: The table background role.
`color`: The packed RGBA color or semantic style slot.
`column`: The target column, or -1 for the current row. | — | — | | [`public static Inno.Editor.ImGui.EditorUiLayout Inno.Editor.ImGui.ImGui.GetLayout()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/ImGui.Drawing.cs#L16) | Copies the current UI layout metrics. | Value metrics valid independently from the native style pointer. | — | | [`public static Inno.Editor.ImGui.EditorUiInput Inno.Editor.ImGui.ImGui.GetInput()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/ImGui.Drawing.cs#L28) | Copies the input facts for this frame. | A neutral value snapshot; no pointer or callback is retained. | — | -| [`public static System.Numerics.Vector4 Inno.Editor.ImGui.ImGui.GetStyleColorValue(Inno.Editor.ImGui.ImGuiCol color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/ImGui.Drawing.cs#L43) | Copies an unmodulated style color for compound presentation.
`color`: The semantic style color slot. | The copied linear vector of UI color components. | — | +| [`public static System.Numerics.Vector4 Inno.Editor.ImGui.ImGui.GetStyleColorValue(Inno.Editor.ImGui.ImGuiCol color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/ImGui.Drawing.cs#L43) | Copies an unmodulated style color for compound presentation.
`color`: The semantic style color slot. | The copied linear vector of UI color components. | — | | [`public static (uint id, System.Numerics.Vector2 position) Inno.Editor.ImGui.ImGui.GetViewport()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/ImGui.Drawing.cs#L55) | Gets the logical viewport identity and copied position for the current window. | The viewport ID and its screen-space origin. | — | | [`public static (float minimumX, float maximumX, float rowMinimum, float rowMaximum) Inno.Editor.ImGui.ImGui.GetTableBounds()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/ImGui.Drawing.cs#L71) | Gets the table and current row bounds needed by row overlays. | The table's horizontal bounds and current row's vertical bounds. | `System.InvalidOperationException`: No valid drawing frame or active table exists. | | [`public static (float minimumX, float maximumX, System.Numerics.Vector2 workMaximum, System.Numerics.Vector2 padding) Inno.Editor.ImGui.ImGui.GetWindowBounds()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/ImGui.Drawing.cs#L89) | Gets copied inner and work bounds for the current window. | Screen-space horizontal bounds and work maximum. | `System.InvalidOperationException`: No valid drawing session or native frame is active. | | [`public static (System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum) Inno.Editor.ImGui.ImGui.GetClipBounds()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/ImGui.Drawing.cs#L105) | Copies the current window's effective clip after parent and viewport clipping. | Screen-space minimum and maximum values for bounding frame-local submission work. | `System.InvalidOperationException`: No valid drawing session or native frame is active. | | [`public static Inno.Editor.ImGui.EditorDrawList Inno.Editor.ImGui.ImGui.GetDrawList()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/ImGui.Drawing.cs#L118) | Borrows drawing commands for the current window and frame without exposing native memory. | A value that rejects use after a window, frame, context or session change. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.HasDragPayload(string protocol)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/ImGui.Drawing.cs#L128) | Checks the active payload's logical protocol without exposing its native buffer.
`protocol`: The exact drag protocol name. | True when a drag of that protocol is currently active. | — | -| [`public static System.Numerics.Vector2 Inno.Editor.ImGui.ImGui.MeasureText(string text, float scale)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/ImGui.Drawing.cs#L150) | Measures literal text at a relative font scale.
`text`: The literal text to measure.
`scale`: Scale relative to the current font. | The copied width and height in UI pixels. | — | -| [`public static void Inno.Editor.ImGui.ImGui.Text(string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L20) | Draws unformatted text.
`text`: Literal text to draw; percent characters are displayed without format-string interpretation. | — | — | -| [`public static bool Inno.Editor.ImGui.ImGui.Button(string label, System.Numerics.Vector2 size = default(System.Numerics.Vector2))`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L38) | Draws a standard button.
`label`: The visible label and optional ImGui identity suffix.
`size`: The requested size, or zero components for automatic sizing. | when the button is activated. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.SmallButton(string label)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L55) | Draws a compact button.
`label`: The visible label and optional ImGui identity suffix. | when the button is activated. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.Checkbox(string label, ref bool value)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L73) | Draws and edits a Boolean value.
`label`: The control label.
`value`: The checked state, updated when the user toggles the control. | when the value changes. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.InputText(string label, ref string value, int capacity = 1024, Inno.Editor.ImGui.ImGuiInputTextFlags flags = Inno.Editor.ImGui.ImGuiInputTextFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L102) | Draws and edits a bounded UTF-8 text value.
`label`: The control label.
`value`: The managed string to display and update.
`capacity`: The positive maximum UTF-8 buffer capacity, including the terminator.
`flags`: Text editing behavior. | when the control reports an edit or submit event. | `System.ArgumentOutOfRangeException`: Thrown when is not positive. | -| [`public static bool Inno.Editor.ImGui.ImGui.InputTextWithHint(string label, string hint, ref string value, int capacity = 1024, Inno.Editor.ImGui.ImGuiInputTextFlags flags = Inno.Editor.ImGui.ImGuiInputTextFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L136) | Draws and edits a bounded UTF-8 text value with placeholder text.
`label`: The control label.
`hint`: The placeholder shown while the value is empty.
`value`: The managed string to display and update.
`capacity`: The positive maximum UTF-8 buffer capacity, including the terminator.
`flags`: Text editing behavior. | when the control reports an edit or submit event. | `System.ArgumentOutOfRangeException`: Thrown when is not positive. | -| [`public static bool Inno.Editor.ImGui.ImGui.InputInt(string label, ref int value, int step = 1, int fastStep = 100, Inno.Editor.ImGui.ImGuiInputTextFlags flags = Inno.Editor.ImGui.ImGuiInputTextFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L168) | Draws and edits an integer value.
`label`: The control label.
`value`: The integer displayed by the control and replaced after an accepted edit.
`step`: Increment used by the ordinary step button.
`fastStep`: Increment used by the accelerated step button.
`flags`: Text editing options for the numeric field. | when the value changes. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.InputFloat(string label, ref float value)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L191) | Draws and edits a floating-point value.
`label`: The control label.
`value`: The number displayed with three fractional digits and replaced after an accepted edit. | when the value changes. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.DragFloat(string label, ref float value, float speed = 1, float minimum = 0, float maximum = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L220) | Draws a floating-point drag control.
`label`: The control label.
`value`: The value to display and update.
`speed`: The drag speed.
`minimum`: The inclusive minimum, or zero with a zero maximum for no clamping.
`maximum`: The inclusive maximum, or zero with a zero minimum for no clamping. | when the value changes. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.SliderFloat(string label, ref float value, float minimum, float maximum, Inno.Editor.ImGui.ImGuiSliderFlags flags = Inno.Editor.ImGui.ImGuiSliderFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L252) | Draws a bounded floating-point slider.
`label`: The control label.
`value`: The value to display and update.
`minimum`: The inclusive minimum.
`maximum`: The inclusive maximum.
`flags`: Slider behavior. | when the value changes. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.ColorEdit4(string label, ref System.Numerics.Vector4 value, Inno.Editor.ImGui.ImGuiColorEditFlags flags = Inno.Editor.ImGui.ImGuiColorEditFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L278) | Draws and edits a four-component color.
`label`: The control label.
`value`: The RGBA value to display and update.
`flags`: Color editing behavior. | when the value changes. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.ColorEditLinear4(string label, ref System.Numerics.Vector4 value, Inno.Editor.ImGui.ImGuiColorEditFlags flags = Inno.Editor.ImGui.ImGuiColorEditFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L308) | Displays a linear RGBA color through a display-sRGB picker and returns edits in linear space.
`label`: The stable identity and visible label of the color control.
`value`: Linear RGB and alpha; only changed RGB channels are decoded, while alpha is never transfer-encoded.
`flags`: Dear ImGui color-edit flags; display modes interpret sRGB values and input storage must be RGB. | True if the display color changed and contains decoded linear RGB. | `System.ArgumentException`: HSV input storage conflicts with the linear-RGB value contract. | -| [`public static bool Inno.Editor.ImGui.ImGui.BeginChild(string id, System.Numerics.Vector2 size = default(System.Numerics.Vector2), Inno.Editor.ImGui.ImGuiChildFlags flags = Inno.Editor.ImGui.ImGuiChildFlags.None, Inno.Editor.ImGui.ImGuiWindowFlags windowFlags = Inno.Editor.ImGui.ImGuiWindowFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L346) | Begins a child region.
`id`: The child identity.
`size`: The requested child size.
`flags`: Child-region behavior.
`windowFlags`: Scroll and window policies for the child. | when child contents should be submitted. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.HasDragPayload(string protocol)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/ImGui.Drawing.cs#L128) | Checks the active payload's logical protocol without exposing its native buffer.
`protocol`: The exact drag protocol name. | True when a drag of that protocol is currently active. | — | +| [`public static System.Numerics.Vector2 Inno.Editor.ImGui.ImGui.MeasureText(string text, float scale)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/ImGui.Drawing.cs#L150) | Measures literal text at a relative font scale.
`text`: The literal text to measure.
`scale`: Scale relative to the current font. | The copied width and height in UI pixels. | — | +| [`public static void Inno.Editor.ImGui.ImGui.Text(string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L20) | Draws unformatted text.
`text`: Literal text to draw; percent characters are displayed without format-string interpretation. | — | — | +| [`public static bool Inno.Editor.ImGui.ImGui.Button(string label, System.Numerics.Vector2 size = default(System.Numerics.Vector2))`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L38) | Draws a standard button.
`label`: The visible label and optional ImGui identity suffix.
`size`: The requested size, or zero components for automatic sizing. | true when the button is activated. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.SmallButton(string label)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L55) | Draws a compact button.
`label`: The visible label and optional ImGui identity suffix. | true when the button is activated. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.Checkbox(string label, ref bool value)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L73) | Draws and edits a Boolean value.
`label`: The control label.
`value`: The checked state, updated when the user toggles the control. | true when the value changes. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.InputText(string label, ref string value, int capacity = 1024, Inno.Editor.ImGui.ImGuiInputTextFlags flags = Inno.Editor.ImGui.ImGuiInputTextFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L102) | Draws and edits a bounded UTF-8 text value.
`label`: The control label.
`value`: The managed string to display and update.
`capacity`: The positive maximum UTF-8 buffer capacity, including the terminator.
`flags`: Text editing behavior. | true when the control reports an edit or submit event. | `System.ArgumentOutOfRangeException`: Thrown when capacity is not positive. | +| [`public static bool Inno.Editor.ImGui.ImGui.InputTextWithHint(string label, string hint, ref string value, int capacity = 1024, Inno.Editor.ImGui.ImGuiInputTextFlags flags = Inno.Editor.ImGui.ImGuiInputTextFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L136) | Draws and edits a bounded UTF-8 text value with placeholder text.
`label`: The control label.
`hint`: The placeholder shown while the value is empty.
`value`: The managed string to display and update.
`capacity`: The positive maximum UTF-8 buffer capacity, including the terminator.
`flags`: Text editing behavior. | true when the control reports an edit or submit event. | `System.ArgumentOutOfRangeException`: Thrown when capacity is not positive. | +| [`public static bool Inno.Editor.ImGui.ImGui.InputInt(string label, ref int value, int step = 1, int fastStep = 100, Inno.Editor.ImGui.ImGuiInputTextFlags flags = Inno.Editor.ImGui.ImGuiInputTextFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L168) | Draws and edits an integer value.
`label`: The control label.
`value`: The integer displayed by the control and replaced after an accepted edit.
`step`: Increment used by the ordinary step button.
`fastStep`: Increment used by the accelerated step button.
`flags`: Text editing options for the numeric field. | true when the value changes. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.InputFloat(string label, ref float value)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L191) | Draws and edits a floating-point value.
`label`: The control label.
`value`: The number displayed with three fractional digits and replaced after an accepted edit. | true when the value changes. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.DragFloat(string label, ref float value, float speed = 1, float minimum = 0, float maximum = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L220) | Draws a floating-point drag control.
`label`: The control label.
`value`: The value to display and update.
`speed`: The drag speed.
`minimum`: The inclusive minimum, or zero with a zero maximum for no clamping.
`maximum`: The inclusive maximum, or zero with a zero minimum for no clamping. | true when the value changes. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.SliderFloat(string label, ref float value, float minimum, float maximum, Inno.Editor.ImGui.ImGuiSliderFlags flags = Inno.Editor.ImGui.ImGuiSliderFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L252) | Draws a bounded floating-point slider.
`label`: The control label.
`value`: The value to display and update.
`minimum`: The inclusive minimum.
`maximum`: The inclusive maximum.
`flags`: Slider behavior. | true when the value changes. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.ColorEdit4(string label, ref System.Numerics.Vector4 value, Inno.Editor.ImGui.ImGuiColorEditFlags flags = Inno.Editor.ImGui.ImGuiColorEditFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L278) | Draws and edits a four-component color.
`label`: The control label.
`value`: The RGBA value to display and update.
`flags`: Color editing behavior. | true when the value changes. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.ColorEditLinear4(string label, ref System.Numerics.Vector4 value, Inno.Editor.ImGui.ImGuiColorEditFlags flags = Inno.Editor.ImGui.ImGuiColorEditFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L308) | Displays a linear RGBA color through a display-sRGB picker and returns edits in linear space.
`label`: The stable identity and visible label of the color control.
`value`: Linear RGB and alpha; only changed RGB channels are decoded, while alpha is never transfer-encoded.
`flags`: Dear ImGui color-edit flags; display modes interpret sRGB values and input storage must be RGB. | True if the display color changed and value contains decoded linear RGB. | `System.ArgumentException`: HSV input storage conflicts with the linear-RGB value contract. | +| [`public static bool Inno.Editor.ImGui.ImGui.BeginChild(string id, System.Numerics.Vector2 size = default(System.Numerics.Vector2), Inno.Editor.ImGui.ImGuiChildFlags flags = Inno.Editor.ImGui.ImGuiChildFlags.None, Inno.Editor.ImGui.ImGuiWindowFlags windowFlags = Inno.Editor.ImGui.ImGuiWindowFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L346) | Begins a child region.
`id`: The child identity.
`size`: The requested child size.
`flags`: Child-region behavior.
`windowFlags`: Scroll and window policies for the child. | true when child contents should be submitted. | — | | [`public static void Inno.Editor.ImGui.ImGui.EndChild()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L359) | Ends the current child region. | — | — | -| [`public static bool Inno.Editor.ImGui.ImGui.BeginTable(string id, int columns, Inno.Editor.ImGui.ImGuiTableFlags flags = Inno.Editor.ImGui.ImGuiTableFlags.None, System.Numerics.Vector2 size = default(System.Numerics.Vector2), float innerWidth = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L386) | Begins a table.
`id`: The table identity.
`columns`: The positive column count.
`flags`: Table behavior.
`size`: The requested outer size.
`innerWidth`: Optional inner scrolling width; zero uses the outer size. | when table contents should be submitted. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.BeginTable(string id, int columns, Inno.Editor.ImGui.ImGuiTableFlags flags = Inno.Editor.ImGui.ImGuiTableFlags.None, System.Numerics.Vector2 size = default(System.Numerics.Vector2), float innerWidth = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L386) | Begins a table.
`id`: The table identity.
`columns`: The positive column count.
`flags`: Table behavior.
`size`: The requested outer size.
`innerWidth`: Optional inner scrolling width; zero uses the outer size. | true when table contents should be submitted. | — | | [`public static void Inno.Editor.ImGui.ImGui.EndTable()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L400) | Ends the current table. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.TableSetupColumn(string label, Inno.Editor.ImGui.ImGuiTableColumnFlags flags = Inno.Editor.ImGui.ImGuiTableColumnFlags.None, float widthOrWeight = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L418) | Declares one table column.
`label`: The column label.
`flags`: Column behavior.
`widthOrWeight`: The initial fixed width or stretch weight. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.TableSetupColumn(string label, Inno.Editor.ImGui.ImGuiTableColumnFlags flags = Inno.Editor.ImGui.ImGuiTableColumnFlags.None, float widthOrWeight = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L418) | Declares one table column.
`label`: The column label.
`flags`: Column behavior.
`widthOrWeight`: The initial fixed width or stretch weight. | — | — | | [`public static void Inno.Editor.ImGui.ImGui.TableHeadersRow()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L430) | Draws the table header row from configured column labels. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.TableNextRow(Inno.Editor.ImGui.ImGuiTableRowFlags flags = Inno.Editor.ImGui.ImGuiTableRowFlags.None, float minimumHeight = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L445) | Advances to the next table row.
`flags`: Row presentation flags.
`minimumHeight`: Minimum row height in UI pixels. | — | — | -| [`public static bool Inno.Editor.ImGui.ImGui.TableNextColumn()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L459) | Advances to the next table column. | when the column is visible. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.BeginCombo(string label, string preview, Inno.Editor.ImGui.ImGuiComboFlags flags = Inno.Editor.ImGui.ImGuiComboFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L480) | Begins a combo popup.
`label`: The control label.
`preview`: The preview text.
`flags`: Combo behavior. | when combo contents should be submitted. | — | +| [`public static void Inno.Editor.ImGui.ImGui.TableNextRow(Inno.Editor.ImGui.ImGuiTableRowFlags flags = Inno.Editor.ImGui.ImGuiTableRowFlags.None, float minimumHeight = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L445) | Advances to the next table row.
`flags`: Row presentation flags.
`minimumHeight`: Minimum row height in UI pixels. | — | — | +| [`public static bool Inno.Editor.ImGui.ImGui.TableNextColumn()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L459) | Advances to the next table column. | true when the column is visible. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.BeginCombo(string label, string preview, Inno.Editor.ImGui.ImGuiComboFlags flags = Inno.Editor.ImGui.ImGuiComboFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L480) | Begins a combo popup.
`label`: The control label.
`preview`: The preview text.
`flags`: Combo behavior. | true when combo contents should be submitted. | — | | [`public static void Inno.Editor.ImGui.ImGui.EndCombo()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L492) | Ends the current combo popup. | — | — | -| [`public static bool Inno.Editor.ImGui.ImGui.Selectable(string label, bool selected = false, Inno.Editor.ImGui.ImGuiSelectableFlags flags = Inno.Editor.ImGui.ImGuiSelectableFlags.None, System.Numerics.Vector2 size = default(System.Numerics.Vector2))`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L516) | Draws one selectable item.
`label`: The visible label and identity.
`selected`: Whether the item is currently selected.
`flags`: Selectable behavior.
`size`: The interaction bounds, or zero for the ordinary content size. | when the item is activated. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.CollapsingHeader(string label, Inno.Editor.ImGui.ImGuiTreeNodeFlags flags = Inno.Editor.ImGui.ImGuiTreeNodeFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L538) | Draws a collapsible section header.
`label`: The visible label and identity.
`flags`: Tree-node behavior. | when the section is open. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.TreeNode(string label, Inno.Editor.ImGui.ImGuiTreeNodeFlags flags = Inno.Editor.ImGui.ImGuiTreeNodeFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L558) | Draws a tree node and pushes its tree scope when it is open.
`label`: The visible label and identity.
`flags`: Tree-node behavior. | when child contents should be submitted. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.Selectable(string label, bool selected = false, Inno.Editor.ImGui.ImGuiSelectableFlags flags = Inno.Editor.ImGui.ImGuiSelectableFlags.None, System.Numerics.Vector2 size = default(System.Numerics.Vector2))`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L516) | Draws one selectable item.
`label`: The visible label and identity.
`selected`: Whether the item is currently selected.
`flags`: Selectable behavior.
`size`: The interaction bounds, or zero for the ordinary content size. | true when the item is activated. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.CollapsingHeader(string label, Inno.Editor.ImGui.ImGuiTreeNodeFlags flags = Inno.Editor.ImGui.ImGuiTreeNodeFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L538) | Draws a collapsible section header.
`label`: The visible label and identity.
`flags`: Tree-node behavior. | true when the section is open. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.TreeNode(string label, Inno.Editor.ImGui.ImGuiTreeNodeFlags flags = Inno.Editor.ImGui.ImGuiTreeNodeFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L558) | Draws a tree node and pushes its tree scope when it is open.
`label`: The visible label and identity.
`flags`: Tree-node behavior. | true when child contents should be submitted. | — | | [`public static void Inno.Editor.ImGui.ImGui.TreePop()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L569) | Ends the current open tree-node scope. | — | — | -| [`public static bool Inno.Editor.ImGui.ImGui.BeginTabBar(string id, Inno.Editor.ImGui.ImGuiTabBarFlags flags = Inno.Editor.ImGui.ImGuiTabBarFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L587) | Begins a tab bar.
`id`: The tab bar identity.
`flags`: Tab-bar behavior. | when tab contents should be submitted. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.BeginTabBar(string id, Inno.Editor.ImGui.ImGuiTabBarFlags flags = Inno.Editor.ImGui.ImGuiTabBarFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L587) | Begins a tab bar.
`id`: The tab bar identity.
`flags`: Tab-bar behavior. | true when tab contents should be submitted. | — | | [`public static void Inno.Editor.ImGui.ImGui.EndTabBar()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L598) | Ends the current tab bar. | — | — | -| [`public static bool Inno.Editor.ImGui.ImGui.BeginTabItem(string label, Inno.Editor.ImGui.ImGuiTabItemFlags flags = Inno.Editor.ImGui.ImGuiTabItemFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L616) | Begins one tab item.
`label`: The tab label and identity.
`flags`: Tab-item behavior. | when tab contents should be submitted. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.BeginTabItem(string label, ref bool isOpen, Inno.Editor.ImGui.ImGuiTabItemFlags flags = Inno.Editor.ImGui.ImGuiTabItemFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L639) | Begins one closeable tab item.
`label`: The tab label and identity.
`isOpen`: Receives whether the tab remains open.
`flags`: Tab-item behavior. | when tab contents should be submitted. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.BeginTabItem(string label, Inno.Editor.ImGui.ImGuiTabItemFlags flags = Inno.Editor.ImGui.ImGuiTabItemFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L616) | Begins one tab item.
`label`: The tab label and identity.
`flags`: Tab-item behavior. | true when tab contents should be submitted. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.BeginTabItem(string label, ref bool isOpen, Inno.Editor.ImGui.ImGuiTabItemFlags flags = Inno.Editor.ImGui.ImGuiTabItemFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L639) | Begins one closeable tab item.
`label`: The tab label and identity.
`isOpen`: Receives whether the tab remains open.
`flags`: Tab-item behavior. | true when tab contents should be submitted. | — | | [`public static void Inno.Editor.ImGui.ImGui.EndTabItem()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L650) | Ends the current tab item. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.OpenPopup(string id, Inno.Editor.ImGui.ImGuiPopupFlags flags = Inno.Editor.ImGui.ImGuiPopupFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L665) | Opens a named popup.
`id`: The popup identity.
`flags`: Popup opening behavior. | — | — | -| [`public static bool Inno.Editor.ImGui.ImGui.BeginPopup(string id, Inno.Editor.ImGui.ImGuiWindowFlags flags = Inno.Editor.ImGui.ImGuiWindowFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L685) | Begins a named popup.
`id`: The popup identity.
`flags`: Popup window behavior. | when popup contents should be submitted. | — | +| [`public static void Inno.Editor.ImGui.ImGui.OpenPopup(string id, Inno.Editor.ImGui.ImGuiPopupFlags flags = Inno.Editor.ImGui.ImGuiPopupFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L665) | Opens a named popup.
`id`: The popup identity.
`flags`: Popup opening behavior. | — | — | +| [`public static bool Inno.Editor.ImGui.ImGui.BeginPopup(string id, Inno.Editor.ImGui.ImGuiWindowFlags flags = Inno.Editor.ImGui.ImGuiWindowFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L685) | Begins a named popup.
`id`: The popup identity.
`flags`: Popup window behavior. | true when popup contents should be submitted. | — | | [`public static void Inno.Editor.ImGui.ImGui.EndPopup()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L696) | Ends the current popup. | — | — | | [`public static void Inno.Editor.ImGui.ImGui.CloseCurrentPopup()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L705) | Closes the current popup. | — | — | | [`public static bool Inno.Editor.ImGui.ImGui.IsAnyPopupOpen()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L720) | Reads whether an open popup or modal currently prevents underlying canvas and list input. | True when any popup is open in this native context, independently of its identifier or nesting. | `System.InvalidOperationException`: No valid drawing session or native frame is active. | -| [`public static void Inno.Editor.ImGui.ImGui.BeginDisabled(bool disabled = true)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L732) | Begins a disabled block.
`disabled`: Whether controls in the block are disabled. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.BeginDisabled(bool disabled = true)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L732) | Begins a disabled block.
`disabled`: Whether controls in the block are disabled. | — | — | | [`public static void Inno.Editor.ImGui.ImGui.EndDisabled()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L741) | Ends the current disabled block. | — | — | | [`public static void Inno.Editor.ImGui.ImGui.BeginGroup()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L750) | Begins an item group. | — | — | | [`public static void Inno.Editor.ImGui.ImGui.EndGroup()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L759) | Ends the current item group. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.PushId(string id)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L771) | Pushes a string identity onto the ImGui ID stack.
`id`: The stable identity used to locate the requested value. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.PushId(int id)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L783) | Pushes an integer identity onto the ImGui ID stack.
`id`: The stable identity used to locate the requested value. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.PushId(string id)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L771) | Pushes a string identity onto the ImGui ID stack.
`id`: The stable identity used to locate the requested value. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.PushId(int id)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L783) | Pushes an integer identity onto the ImGui ID stack.
`id`: The stable identity used to locate the requested value. | — | — | | [`public static void Inno.Editor.ImGui.ImGui.PopId()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L792) | Pops one identity from the ImGui ID stack. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.PushStyleColor(Inno.Editor.ImGui.ImGuiCol color, System.Numerics.Vector4 value)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L807) | Pushes one color override.
`color`: The style color slot.
`value`: The linear RGBA value. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.PopStyleColor(int count = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L821) | Pops color overrides.
`count`: The positive number of overrides to pop. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.PushStyleVar(Inno.Editor.ImGui.ImGuiStyleVar style, float value)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L836) | Pushes one scalar style override.
`style`: The style variable.
`value`: The scalar value. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.PushStyleVar(Inno.Editor.ImGui.ImGuiStyleVar style, System.Numerics.Vector2 value)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L853) | Pushes one two-component style override.
`style`: The style variable.
`value`: The vector value. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.PopStyleVar(int count = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L867) | Pops style-variable overrides.
`count`: The positive number of overrides to pop. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.SameLine(float offset = 0, float spacing = -1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L882) | Places the next item on the same line.
`offset`: The horizontal offset from the line start, or zero for automatic placement.
`spacing`: The explicit spacing, or a negative value for the current style spacing. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.PushStyleColor(Inno.Editor.ImGui.ImGuiCol color, System.Numerics.Vector4 value)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L807) | Pushes one color override.
`color`: The style color slot.
`value`: The linear RGBA value. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.PopStyleColor(int count = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L821) | Pops color overrides.
`count`: The positive number of overrides to pop. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.PushStyleVar(Inno.Editor.ImGui.ImGuiStyleVar style, float value)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L836) | Pushes one scalar style override.
`style`: The style variable.
`value`: The scalar value. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.PushStyleVar(Inno.Editor.ImGui.ImGuiStyleVar style, System.Numerics.Vector2 value)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L853) | Pushes one two-component style override.
`style`: The style variable.
`value`: The vector value. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.PopStyleVar(int count = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L867) | Pops style-variable overrides.
`count`: The positive number of overrides to pop. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.SameLine(float offset = 0, float spacing = -1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L882) | Places the next item on the same line.
`offset`: The horizontal offset from the line start, or zero for automatic placement.
`spacing`: The explicit spacing, or a negative value for the current style spacing. | — | — | | [`public static void Inno.Editor.ImGui.ImGui.Separator()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L893) | Draws a horizontal separator. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.SeparatorText(string label)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L905) | Draws a labeled horizontal separator.
`label`: The label text validated by the separator text operation. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.SeparatorText(string label)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L905) | Draws a labeled horizontal separator.
`label`: The label text validated by the separator text operation. | — | — | | [`public static void Inno.Editor.ImGui.ImGui.Spacing()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L914) | Adds one standard vertical spacing unit. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.Dummy(System.Numerics.Vector2 size)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L926) | Advances layout by an invisible size.
`size`: The size consumed by dummy; ownership remains with the caller unless explicitly stated otherwise. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.SetNextItemWidth(float width)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L938) | Sets the width of the next item.
`width`: The width in logical units or pixels required by this operation. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.Dummy(System.Numerics.Vector2 size)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L926) | Advances layout by an invisible size.
`size`: The size consumed by dummy; ownership remains with the caller unless explicitly stated otherwise. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.SetNextItemWidth(float width)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L938) | Sets the width of the next item.
`width`: The width in logical units or pixels required by this operation. | — | — | | [`public static void Inno.Editor.ImGui.ImGui.FocusNextItem()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L950) | Requests keyboard focus for the next submitted item in the current frame and window. | — | `System.InvalidOperationException`: No matching owner-thread drawing session is active. | | [`public static System.Numerics.Vector2 Inno.Editor.ImGui.ImGui.GetContentRegionAvailable()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L962) | Gets the remaining content size in the current region. | The remaining local width and height. | — | | [`public static System.Numerics.Vector2 Inno.Editor.ImGui.ImGui.GetCursorPosition()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L974) | Gets the current local cursor position. | The local cursor position. | — | -| [`public static void Inno.Editor.ImGui.ImGui.SetCursorPosition(System.Numerics.Vector2 position)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L986) | Sets the current local cursor position.
`position`: The position consumed by set cursor position; ownership remains with the caller unless explicitly stated otherwise. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.SetCursorPosition(System.Numerics.Vector2 position)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L986) | Sets the current local cursor position.
`position`: The position consumed by set cursor position; ownership remains with the caller unless explicitly stated otherwise. | — | — | | [`public static System.Numerics.Vector2 Inno.Editor.ImGui.ImGui.GetCursorScreenPosition()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L998) | Gets the current screen-space cursor position. | The screen-space cursor position. | — | | [`public static System.Numerics.Vector2 Inno.Editor.ImGui.ImGui.GetItemMinimum()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1010) | Gets the minimum screen-space corner of the previous item. | The item minimum corner. | — | | [`public static System.Numerics.Vector2 Inno.Editor.ImGui.ImGui.GetItemMaximum()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1022) | Gets the maximum screen-space corner of the previous item. | The item maximum corner. | — | -| [`public static System.Numerics.Vector2 Inno.Editor.ImGui.ImGui.MeasureText(string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1037) | Measures text using the current font.
`text`: The text text validated by the measure text operation. | The measured width and height. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.IsItemHovered(Inno.Editor.ImGui.ImGuiHoveredFlags flags = Inno.Editor.ImGui.ImGuiHoveredFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1052) | Gets whether the previous item is hovered.
`flags`: Hovered query behavior. | when the query succeeds. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.IsItemActive()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1064) | Gets whether the previous item is active. | while the item owns an active interaction. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.IsItemClicked(Inno.Editor.ImGui.ImGuiMouseButton button = Inno.Editor.ImGui.ImGuiMouseButton.Left)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1079) | Gets whether the previous item was clicked with a mouse button.
`button`: The mouse button to query. | when the item was clicked. | — | -| [`public static bool Inno.Editor.ImGui.ImGui.IsMouseButtonDown(Inno.Editor.ImGui.ImGuiMouseButton button = Inno.Editor.ImGui.ImGuiMouseButton.Left)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1094) | Gets whether a mouse button is held in the current Editor UI frame, including input consumed by UI controls.
`button`: The UI mouse button to query. | True while the button is held; callers must also check their item's active or hovered state before editing. | — | -| [`public static System.Numerics.Vector2 Inno.Editor.ImGui.ImGui.GetMouseDragDelta(Inno.Editor.ImGui.ImGuiMouseButton button = Inno.Editor.ImGui.ImGuiMouseButton.Left, float threshold = -1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1113) | Gets accumulated pointer displacement from the current UI drag's starting position for timeline and canvas controls.
`button`: The button that owns the drag.
`threshold`: Movement required to start dragging, or a negative value to use the Editor's configured threshold. | Displacement in UI coordinates, or zero before the drag threshold is crossed or when no drag is available. The value is cumulative; it must be applied to a captured starting value, not added again each frame. | — | -| [`public static uint Inno.Editor.ImGui.ImGui.ToPackedColor(System.Numerics.Vector4 color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1130) | Converts a floating-point RGBA color to Dear ImGui packed color order.
`color`: The color consumed by to packed color; ownership remains with the caller unless explicitly stated otherwise. | The packed color value. | — | -| [`public static void Inno.Editor.ImGui.ImGui.DrawLine(System.Numerics.Vector2 start, System.Numerics.Vector2 end, uint color, float thickness = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1153) | Adds a line to the current window draw list.
`start`: The screen-space start point.
`end`: The screen-space end point.
`color`: The packed ImGui color.
`thickness`: The line thickness. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.DrawRectangle(System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, uint color, float rounding = 0, float thickness = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1181) | Adds a rectangle outline to the current window draw list.
`minimum`: The screen-space minimum corner.
`maximum`: The screen-space maximum corner.
`color`: The packed ImGui color.
`rounding`: The corner rounding radius.
`thickness`: The outline thickness. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.DrawFilledRectangle(System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, uint color, float rounding = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1207) | Adds a filled rectangle to the current window draw list.
`minimum`: The screen-space minimum corner.
`maximum`: The screen-space maximum corner.
`color`: The packed ImGui color.
`rounding`: The corner rounding radius. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.DrawCubicCurve(System.Numerics.Vector2 start, System.Numerics.Vector2 firstControl, System.Numerics.Vector2 secondControl, System.Numerics.Vector2 end, uint color, float thickness = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1238) | Draws a cubic curve without exposing a native draw list or borrowed pointer.
`start`: The first screen-space endpoint.
`firstControl`: The control point beside the first endpoint.
`secondControl`: The control point beside the final endpoint.
`end`: The final screen-space endpoint.
`color`: The packed presentation color.
`thickness`: The positive stroke width. | — | — | -| [`public static void Inno.Editor.ImGui.ImGui.DrawText(System.Numerics.Vector2 position, uint color, string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1263) | Adds text to the current window draw list.
`position`: The screen-space text origin.
`color`: The packed ImGui color.
`text`: The text to draw. | — | — | +| [`public static System.Numerics.Vector2 Inno.Editor.ImGui.ImGui.MeasureText(string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1037) | Measures text using the current font.
`text`: The text text validated by the measure text operation. | The measured width and height. | — | +| [`public static System.Numerics.Vector2 Inno.Editor.ImGui.ImGui.MeasureWrappedText(string text, float wrapWidth)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1058) | Measures literal text using the same current font and wrap width as wrapped drawing.
`text`: The literal text, including explicit line breaks.
`wrapWidth`: The available width in already scaled presentation coordinates. | The copied natural text extent at the specified width. | `System.ArgumentOutOfRangeException`: The width is not finite and positive.
`System.InvalidOperationException`: The owning UI thread, frame or native context is not active.
`System.ObjectDisposedException`: The owning UI session has retired. | +| [`public static bool Inno.Editor.ImGui.ImGui.IsItemHovered(Inno.Editor.ImGui.ImGuiHoveredFlags flags = Inno.Editor.ImGui.ImGuiHoveredFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1084) | Gets whether the previous item is hovered.
`flags`: Hovered query behavior. | true when the query succeeds. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.IsItemActive()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1096) | Gets whether the previous item is active. | true while the item owns an active interaction. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.IsItemClicked(Inno.Editor.ImGui.ImGuiMouseButton button = Inno.Editor.ImGui.ImGuiMouseButton.Left)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1111) | Gets whether the previous item was clicked with a mouse button.
`button`: The mouse button to query. | true when the item was clicked. | — | +| [`public static bool Inno.Editor.ImGui.ImGui.IsMouseButtonDown(Inno.Editor.ImGui.ImGuiMouseButton button = Inno.Editor.ImGui.ImGuiMouseButton.Left)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1126) | Gets whether a mouse button is held in the current Editor UI frame, including input consumed by UI controls.
`button`: The UI mouse button to query. | True while the button is held; callers must also check their item's active or hovered state before editing. | — | +| [`public static System.Numerics.Vector2 Inno.Editor.ImGui.ImGui.GetMouseDragDelta(Inno.Editor.ImGui.ImGuiMouseButton button = Inno.Editor.ImGui.ImGuiMouseButton.Left, float threshold = -1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1145) | Gets accumulated pointer displacement from the current UI drag's starting position for timeline and canvas controls.
`button`: The button that owns the drag.
`threshold`: Movement required to start dragging, or a negative value to use the Editor's configured threshold. | Displacement in UI coordinates, or zero before the drag threshold is crossed or when no drag is available. The value is cumulative; it must be applied to a captured starting value, not added again each frame. | — | +| [`public static uint Inno.Editor.ImGui.ImGui.ToPackedColor(System.Numerics.Vector4 color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1162) | Converts a floating-point RGBA color to Dear ImGui packed color order.
`color`: The color consumed by to packed color; ownership remains with the caller unless explicitly stated otherwise. | The packed color value. | — | +| [`public static void Inno.Editor.ImGui.ImGui.DrawLine(System.Numerics.Vector2 start, System.Numerics.Vector2 end, uint color, float thickness = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1185) | Adds a line to the current window draw list.
`start`: The screen-space start point.
`end`: The screen-space end point.
`color`: The packed ImGui color.
`thickness`: The line thickness. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.DrawRectangle(System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, uint color, float rounding = 0, float thickness = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1213) | Adds a rectangle outline to the current window draw list.
`minimum`: The screen-space minimum corner.
`maximum`: The screen-space maximum corner.
`color`: The packed ImGui color.
`rounding`: The corner rounding radius.
`thickness`: The outline thickness. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.DrawFilledRectangle(System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, uint color, float rounding = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1239) | Adds a filled rectangle to the current window draw list.
`minimum`: The screen-space minimum corner.
`maximum`: The screen-space maximum corner.
`color`: The packed ImGui color.
`rounding`: The corner rounding radius. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.DrawCubicCurve(System.Numerics.Vector2 start, System.Numerics.Vector2 firstControl, System.Numerics.Vector2 secondControl, System.Numerics.Vector2 end, uint color, float thickness = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1270) | Draws a cubic curve without exposing a native draw list or borrowed pointer.
`start`: The first screen-space endpoint.
`firstControl`: The control point beside the first endpoint.
`secondControl`: The control point beside the final endpoint.
`end`: The final screen-space endpoint.
`color`: The packed presentation color.
`thickness`: The positive stroke width. | — | — | +| [`public static void Inno.Editor.ImGui.ImGui.DrawText(System.Numerics.Vector2 position, uint color, string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs#L1295) | Adds text to the current window draw list.
`position`: The screen-space text origin.
`color`: The packed ImGui color.
`text`: The text to draw. | — | — | | [`public enum Inno.Editor.ImGui.ImGuiButtonFlags : int`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/Options/ImGuiButtonFlags.cs#L8) | Defines the supported button flags choices at the Editor presentation boundary. | — | — | | [`Inno.Editor.ImGui.ImGuiButtonFlags.None = 0`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/Options/ImGuiButtonFlags.cs#L13) | Uses the ordinary behavior without additional options. | — | — | | [`Inno.Editor.ImGui.ImGuiButtonFlags.MouseButtonLeft = 1`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/Options/ImGuiButtonFlags.cs#L17) | React on left mouse button (default) | — | — | @@ -2201,44 +2260,44 @@ static void DrawHelp() | [`Inno.Editor.ImGui.ImGuiWindowFlags.Modal = 134217728`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/Options/ImGuiWindowFlags.cs#L125) | Don't use! For internal use by BeginPopupModal() | — | — | | [`Inno.Editor.ImGui.ImGuiWindowFlags.ChildMenu = 268435456`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Controls/Options/ImGuiWindowFlags.cs#L129) | Don't use! For internal use by BeginMenu() | — | — | | [`public readonly struct Inno.Editor.ImGui.EditorDrawList`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L11) | A pointer-free drawing borrow valid only in its original window, UI session and frame. | — | — | -| [`public void Inno.Editor.ImGui.EditorDrawList.Line(System.Numerics.Vector2 start, System.Numerics.Vector2 end, uint color, float thickness = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L39) | Adds a straight screen-space stroke.
`start`: The first endpoint.
`end`: The final endpoint.
`color`: Packed RGBA color.
`thickness`: Stroke width in UI pixels. | — | — | -| [`public void Inno.Editor.ImGui.EditorDrawList.FilledRectangle(System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, uint color, float rounding = 0, bool topCornersOnly = false)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L63) | Adds a filled rectangular surface.
`minimum`: The upper-left corner.
`maximum`: The lower-right corner.
`color`: Packed RGBA color.
`rounding`: Corner radius.
`topCornersOnly`: Whether only the two top corners should be rounded. | — | — | -| [`public void Inno.Editor.ImGui.EditorDrawList.Rectangle(System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, uint color, float rounding = 0, float thickness = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L88) | Adds a rectangular outline.
`minimum`: The upper-left corner.
`maximum`: The lower-right corner.
`color`: Packed RGBA color.
`rounding`: Corner radius.
`thickness`: Stroke width in UI pixels. | — | — | -| [`public void Inno.Editor.ImGui.EditorDrawList.FilledCircle(System.Numerics.Vector2 center, float radius, uint color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L107) | Adds a filled circle with backend-selected tessellation.
`center`: The screen-space center.
`radius`: The nonnegative radius.
`color`: Packed RGBA color. | — | — | -| [`public void Inno.Editor.ImGui.EditorDrawList.Text(System.Numerics.Vector2 position, uint color, string text, float scale = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L131) | Adds literal text using the current font and an explicit scale.
`position`: Screen-space text origin.
`color`: Packed RGBA color.
`text`: Literal managed text; encoded only for this synchronous call.
`scale`: Positive scale relative to the current font size. | — | — | -| [`public void Inno.Editor.ImGui.EditorDrawList.PushClip(System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, bool intersect = true)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L157) | Restricts subsequent drawing to one screen rectangle.
`minimum`: The clip minimum.
`maximum`: The clip maximum.
`intersect`: Whether to intersect the enclosing clip. | — | — | +| [`public void Inno.Editor.ImGui.EditorDrawList.Line(System.Numerics.Vector2 start, System.Numerics.Vector2 end, uint color, float thickness = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L39) | Adds a straight screen-space stroke.
`start`: The first endpoint.
`end`: The final endpoint.
`color`: Packed RGBA color.
`thickness`: Stroke width in UI pixels. | — | — | +| [`public void Inno.Editor.ImGui.EditorDrawList.FilledRectangle(System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, uint color, float rounding = 0, bool topCornersOnly = false)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L63) | Adds a filled rectangular surface.
`minimum`: The upper-left corner.
`maximum`: The lower-right corner.
`color`: Packed RGBA color.
`rounding`: Corner radius.
`topCornersOnly`: Whether only the two top corners should be rounded. | — | — | +| [`public void Inno.Editor.ImGui.EditorDrawList.Rectangle(System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, uint color, float rounding = 0, float thickness = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L88) | Adds a rectangular outline.
`minimum`: The upper-left corner.
`maximum`: The lower-right corner.
`color`: Packed RGBA color.
`rounding`: Corner radius.
`thickness`: Stroke width in UI pixels. | — | — | +| [`public void Inno.Editor.ImGui.EditorDrawList.FilledCircle(System.Numerics.Vector2 center, float radius, uint color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L107) | Adds a filled circle with backend-selected tessellation.
`center`: The screen-space center.
`radius`: The nonnegative radius.
`color`: Packed RGBA color. | — | — | +| [`public void Inno.Editor.ImGui.EditorDrawList.Text(System.Numerics.Vector2 position, uint color, string text, float scale = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L131) | Adds literal text using the current font and an explicit scale.
`position`: Screen-space text origin.
`color`: Packed RGBA color.
`text`: Literal managed text; encoded only for this synchronous call.
`scale`: Positive scale relative to the current font size. | — | — | +| [`public void Inno.Editor.ImGui.EditorDrawList.PushClip(System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, bool intersect = true)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L157) | Restricts subsequent drawing to one screen rectangle.
`minimum`: The clip minimum.
`maximum`: The clip maximum.
`intersect`: Whether to intersect the enclosing clip. | — | — | | [`public void Inno.Editor.ImGui.EditorDrawList.PopClip()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L169) | Restores the enclosing clip after a matching PushClip. | — | — | -| [`public void Inno.Editor.ImGui.EditorDrawList.SplitChannels(int count)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L176) | Begins ordered draw channels within this window.
`count`: The positive number of layers. | — | — | -| [`public void Inno.Editor.ImGui.EditorDrawList.SetChannel(int index)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L188) | Selects a channel from the current split.
`index`: The zero-based channel. | — | — | +| [`public void Inno.Editor.ImGui.EditorDrawList.SplitChannels(int count)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L176) | Begins ordered draw channels within this window.
`count`: The positive number of layers. | — | — | +| [`public void Inno.Editor.ImGui.EditorDrawList.SetChannel(int index)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L188) | Selects a channel from the current split.
`index`: The zero-based channel. | — | — | | [`public void Inno.Editor.ImGui.EditorDrawList.MergeChannels()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Drawing/EditorDrawList.cs#L192) | Merges the current split back into ordered draw commands. | — | — | | [`public static class Inno.Editor.ImGui.EditorDragDropRenderer`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L12) | Bridges managed editor drag sessions to the native ImGui payload API. | — | — | -| [`public static bool Inno.Editor.ImGui.EditorDragDropRenderer.Source(Inno.Editor.Interactions.EditorInteraction interaction, Inno.Editor.Interactions.EditorDragData data, System.Action? drawPreview = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L30) | Publishes managed drag data for the most recently submitted ImGui item.
`interaction`: The interaction area and target that produced the drag source.
`data`: The managed drag data published by the source.
`drawPreview`: An optional callback that draws the native drag preview. | while the item is an active drag source. | — | -| [`public static Inno.Editor.ImGui.EditorDropWidgetResult Inno.Editor.ImGui.EditorDragDropRenderer.Target(Inno.Editor.Interactions.EditorInteraction interaction, Inno.Editor.Interactions.EditorDropPlacement placement = Inno.Editor.Interactions.EditorDropPlacement.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L51) | Evaluates and, on delivery, accepts a managed drag on the most recently submitted ImGui item.
`interaction`: The interaction area and managed drop target.
`placement`: The requested position relative to the target. | The native preview state together with the managed compatibility and delivery results. | — | +| [`public static bool Inno.Editor.ImGui.EditorDragDropRenderer.Source(Inno.Editor.Interactions.EditorInteraction interaction, Inno.Editor.Interactions.EditorDragData data, System.Action? drawPreview = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L30) | Publishes managed drag data for the most recently submitted ImGui item.
`interaction`: The interaction area and target that produced the drag source.
`data`: The managed drag data published by the source.
`drawPreview`: An optional callback that draws the native drag preview. | true while the item is an active drag source. | — | +| [`public static Inno.Editor.ImGui.EditorDropWidgetResult Inno.Editor.ImGui.EditorDragDropRenderer.Target(Inno.Editor.Interactions.EditorInteraction interaction, Inno.Editor.Interactions.EditorDropPlacement placement = Inno.Editor.Interactions.EditorDropPlacement.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L51) | Evaluates and, on delivery, accepts a managed drag on the most recently submitted ImGui item.
`interaction`: The interaction area and managed drop target.
`placement`: The requested position relative to the target. | The native preview state together with the managed compatibility and delivery results. | — | | [`public readonly record struct Inno.Editor.ImGui.EditorDropWidgetResult : System.IEquatable`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L74) | Reports the preview and delivery state of an ImGui editor drop target. | — | — | -| [`public Inno.Editor.ImGui.EditorDropWidgetResult.EditorDropWidgetResult(bool isPreviewing, Inno.Editor.Interactions.EditorDropStatus status, Inno.Editor.Interactions.EditorDropResult result)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L88) | Creates a combined native-preview and managed-drop result.
`isPreviewing`: Whether a compatible native payload is currently hovering the target.
`status`: The compatibility and visual state returned by the managed drop router.
`result`: The result produced when the payload was delivered. | — | — | +| [`public Inno.Editor.ImGui.EditorDropWidgetResult.EditorDropWidgetResult(bool isPreviewing, Inno.Editor.Interactions.EditorDropStatus status, Inno.Editor.Interactions.EditorDropResult result)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L88) | Creates a combined native-preview and managed-drop result.
`isPreviewing`: Whether a compatible native payload is currently hovering the target.
`status`: The compatibility and visual state returned by the managed drop router.
`result`: The result produced when the payload was delivered. | — | — | | [`public bool Inno.Editor.ImGui.EditorDropWidgetResult.isPreviewing { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L101) | Gets whether a compatible native payload is hovering the target. | — | — | | [`public Inno.Editor.Interactions.EditorDropStatus Inno.Editor.ImGui.EditorDropWidgetResult.status { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L105) | Gets the managed drop compatibility status. | — | — | | [`public Inno.Editor.Interactions.EditorDropResult Inno.Editor.ImGui.EditorDropWidgetResult.result { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L109) | Gets the delivered drop result. | — | — | | [`public static Inno.Editor.ImGui.EditorDropWidgetResult Inno.Editor.ImGui.EditorDropWidgetResult.none { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L113) | Gets an inactive drop target result. | — | — | | [`public override string Inno.Editor.ImGui.EditorDropWidgetResult.ToString()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L74) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | -| [`public static bool Inno.Editor.ImGui.EditorDropWidgetResult.operator !=(Inno.Editor.ImGui.EditorDropWidgetResult left, Inno.Editor.ImGui.EditorDropWidgetResult right)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L74) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.ImGui.EditorDropWidgetResult.operator ==(Inno.Editor.ImGui.EditorDropWidgetResult left, Inno.Editor.ImGui.EditorDropWidgetResult right)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L74) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.ImGui.EditorDropWidgetResult.operator !=(Inno.Editor.ImGui.EditorDropWidgetResult left, Inno.Editor.ImGui.EditorDropWidgetResult right)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L74) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.ImGui.EditorDropWidgetResult.operator ==(Inno.Editor.ImGui.EditorDropWidgetResult left, Inno.Editor.ImGui.EditorDropWidgetResult right)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L74) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.ImGui.EditorDropWidgetResult.GetHashCode()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L74) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.ImGui.EditorDropWidgetResult.Equals(object obj)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L74) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.ImGui.EditorDropWidgetResult.Equals(Inno.Editor.ImGui.EditorDropWidgetResult other)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L74) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | +| [`public override bool Inno.Editor.ImGui.EditorDropWidgetResult.Equals(object obj)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L74) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.ImGui.EditorDropWidgetResult.Equals(Inno.Editor.ImGui.EditorDropWidgetResult other)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorDragDropRenderer.cs#L74) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | | [`public sealed class Inno.Editor.ImGui.EditorGameInputCapture`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorGameInputCapture.cs#L13) | Routes platform input to the Play session only while the visible Game View owns focus. | — | — | -| [`public Inno.Editor.ImGui.EditorGameInputCapture.EditorGameInputCapture(System.Func resolveWindow)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorGameInputCapture.cs#L35) | Creates a capture policy using a presentation viewport to platform window resolver.
`resolveWindow`: Returns a live window ID for a viewport, or null when absent. | — | `System.ArgumentNullException`: Thrown when the resolver is null. | +| [`public Inno.Editor.ImGui.EditorGameInputCapture.EditorGameInputCapture(System.Func resolveWindow)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorGameInputCapture.cs#L35) | Creates a capture policy using a presentation viewport to platform window resolver.
`resolveWindow`: Returns a live window ID for a viewport, or null when absent. | — | `System.ArgumentNullException`: Thrown when the resolver is null. | | [`public void Inno.Editor.ImGui.EditorGameInputCapture.BeginFrame()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorGameInputCapture.cs#L43) | Starts a presentation pass in which the visible Game View must report its current bounds. | — | — | -| [`public bool Inno.Editor.ImGui.EditorGameInputCapture.Report(uint viewportId, System.Numerics.Vector2 origin, System.Numerics.Vector2 size, bool focused, bool hovered)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorGameInputCapture.cs#L66) | Reports the Game View image in coordinates local to its platform window.
`viewportId`: The presentation viewport containing the Game View.
`origin`: The image's upper-left corner relative to that window.
`size`: The visible image size in logical pixels.
`focused`: Whether the Game View is selected and its platform window has focus.
`hovered`: Whether the image is inside the frontmost hovered ImGui window. | when the Game View and its platform window both own focus. | — | +| [`public bool Inno.Editor.ImGui.EditorGameInputCapture.Report(uint viewportId, System.Numerics.Vector2 origin, System.Numerics.Vector2 size, bool focused, bool hovered)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorGameInputCapture.cs#L66) | Reports the Game View image in coordinates local to its platform window.
`viewportId`: The presentation viewport containing the Game View.
`origin`: The image's upper-left corner relative to that window.
`size`: The visible image size in logical pixels.
`focused`: Whether the Game View is selected and its platform window has focus.
`hovered`: Whether the image is inside the frontmost hovered ImGui window. | true when the Game View and its platform window both own focus. | — | | [`public uint Inno.Editor.ImGui.EditorGameInputCapture.CompleteFrame()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorGameInputCapture.cs#L89) | Ends a presentation pass and identifies input that must be released after focus loss. | The former platform window ID to reset, or zero if no reset is needed. | — | -| [`public Inno.Core.Events.Event? Inno.Editor.ImGui.EditorGameInputCapture.Route(Inno.Core.Events.Event evnt)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorGameInputCapture.cs#L126) | Filters an engine event through the current Game View focus and pointer bounds.
`evnt`: The original backend-neutral platform event. | A routed event or a synthetic focus reset, or null when the Game View must not receive input. | `System.ArgumentNullException`: Thrown when the event is null. | +| [`public Inno.Core.Events.Event? Inno.Editor.ImGui.EditorGameInputCapture.Route(Inno.Core.Events.Event evnt)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorGameInputCapture.cs#L126) | Filters an engine event through the current Game View focus and pointer bounds.
`evnt`: The original backend-neutral platform event. | A routed event or a synthetic focus reset, or null when the Game View must not receive input. | `System.ArgumentNullException`: Thrown when the event is null. | | [`public sealed class Inno.Editor.ImGui.EditorMenuRenderer`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorMenuRenderer.cs#L15) | Renders immutable editor menu models through ImGui. | — | — | -| [`public bool Inno.Editor.ImGui.EditorMenuRenderer.ContextMenu(string id, Inno.Editor.Interactions.EditorInteraction interaction)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorMenuRenderer.cs#L43) | Draws a resolved right-click menu for the most recently submitted ImGui item.
`id`: The stable popup identifier in the current ImGui ID scope.
`interaction`: The interaction area and optional operation target. | while the context popup is open and its items were drawn. | — | -| [`public bool Inno.Editor.ImGui.EditorMenuRenderer.ContextMenu(string id, Inno.Editor.Interactions.EditorInteraction scopeInteraction, Inno.Editor.Interactions.EditorInteraction itemInteraction)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorMenuRenderer.cs#L88) | Draws one context popup composed from an item interaction and its containing-scope interaction.
`id`: Stable popup identifier in the current ImGui ID scope.
`scopeInteraction`: Container interaction whose commands are shown first, such as creation commands for a directory.
`itemInteraction`: Selected-item interaction whose commands are shown after the container commands. | while the context popup is open and at least one command group was drawn. | — | -| [`public bool Inno.Editor.ImGui.EditorMenuRenderer.WindowContextMenu(string id, Inno.Editor.Interactions.EditorInteraction interaction)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorMenuRenderer.cs#L132) | Draws a resolved right-click menu when the current ImGui window's unoccupied background is clicked.
`id`: The stable popup identifier in the current ImGui ID scope.
`interaction`: The interaction area and directory target for the background operation. | while the background context popup is open and its items were drawn. | — | -| [`public void Inno.Editor.ImGui.EditorMenuRenderer.MainMenu(Inno.Editor.Interactions.EditorInteraction interaction)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorMenuRenderer.cs#L215) | Draws the complete editor main menu bar for the supplied menu context.
`interaction`: The main-menu interaction area. | — | — | -| [`public void Inno.Editor.ImGui.EditorMenuRenderer.DrawItems(Inno.Editor.Interactions.EditorInteraction interaction, System.Collections.Generic.IReadOnlyList items)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorMenuRenderer.cs#L309) | Recursively draws resolved menu nodes into the currently open popup or menu.
`interaction`: The interaction used to resolve shortcuts and enqueue selected actions.
`items`: The immutable menu nodes to draw in display order. | — | — | -| [`public bool Inno.Editor.ImGui.EditorMenuRenderer.DrawSearchItems(Inno.Editor.Interactions.EditorInteraction interaction, System.Collections.Generic.IReadOnlyList items, string search)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorMenuRenderer.cs#L364) | Draws matching leaf commands as a flat searchable list.
`interaction`: The interaction used to enqueue selected actions.
`items`: The immutable menu tree whose leaves should be searched.
`search`: The case-insensitive text matched against each slash-delimited leaf path. | when a command was selected. | — | +| [`public bool Inno.Editor.ImGui.EditorMenuRenderer.ContextMenu(string id, Inno.Editor.Interactions.EditorInteraction interaction)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorMenuRenderer.cs#L43) | Draws a resolved right-click menu for the most recently submitted ImGui item.
`id`: The stable popup identifier in the current ImGui ID scope.
`interaction`: The interaction area and optional operation target. | true while the context popup is open and its items were drawn. | — | +| [`public bool Inno.Editor.ImGui.EditorMenuRenderer.ContextMenu(string id, Inno.Editor.Interactions.EditorInteraction scopeInteraction, Inno.Editor.Interactions.EditorInteraction itemInteraction)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorMenuRenderer.cs#L88) | Draws one context popup composed from an item interaction and its containing-scope interaction.
`id`: Stable popup identifier in the current ImGui ID scope.
`scopeInteraction`: Container interaction whose commands are shown first, such as creation commands for a directory.
`itemInteraction`: Selected-item interaction whose commands are shown after the container commands. | true while the context popup is open and at least one command group was drawn. | — | +| [`public bool Inno.Editor.ImGui.EditorMenuRenderer.WindowContextMenu(string id, Inno.Editor.Interactions.EditorInteraction interaction)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorMenuRenderer.cs#L132) | Draws a resolved right-click menu when the current ImGui window's unoccupied background is clicked.
`id`: The stable popup identifier in the current ImGui ID scope.
`interaction`: The interaction area and directory target for the background operation. | true while the background context popup is open and its items were drawn. | — | +| [`public void Inno.Editor.ImGui.EditorMenuRenderer.MainMenu(Inno.Editor.Interactions.EditorInteraction interaction)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorMenuRenderer.cs#L215) | Draws the complete editor main menu bar for the supplied menu context.
`interaction`: The main-menu interaction area. | — | — | +| [`public void Inno.Editor.ImGui.EditorMenuRenderer.DrawItems(Inno.Editor.Interactions.EditorInteraction interaction, System.Collections.Generic.IReadOnlyList items)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorMenuRenderer.cs#L309) | Recursively draws resolved menu nodes into the currently open popup or menu.
`interaction`: The interaction used to resolve shortcuts and enqueue selected actions.
`items`: The immutable menu nodes to draw in display order. | — | — | +| [`public bool Inno.Editor.ImGui.EditorMenuRenderer.DrawSearchItems(Inno.Editor.Interactions.EditorInteraction interaction, System.Collections.Generic.IReadOnlyList items, string search)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorMenuRenderer.cs#L364) | Draws matching leaf commands as a flat searchable list.
`interaction`: The interaction used to enqueue selected actions.
`items`: The immutable menu tree whose leaves should be searched.
`search`: The case-insensitive text matched against each slash-delimited leaf path. | true when a command was selected. | — | | [`public readonly struct Inno.Editor.ImGui.EditorUiInput`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorUiInput.cs#L8) | Copies frame input facts used by presentation without exposing native input storage. | — | — | | [`public bool Inno.Editor.ImGui.EditorUiInput.alt { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorUiInput.cs#L13) | Gets whether Alt is held. | — | — | | [`public bool Inno.Editor.ImGui.EditorUiInput.control { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorUiInput.cs#L17) | Gets whether the physical Control modifier is held, independently of native shortcut conventions. | — | — | @@ -2258,16 +2317,16 @@ static void DrawHelp() | [`public System.IDisposable Inno.Editor.ImGui.EditorUiSession.Enter()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorUiSession.cs#L81) | Activates this session for a synchronous callback while preserving the enclosing scope. | An owner-thread scope that must be released in reverse activation order. | `System.ObjectDisposedException`: The session has retired.
`System.InvalidOperationException`: The caller is not the owner thread. | | [`public void Inno.Editor.ImGui.EditorUiSession.Dispose()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorUiSession.cs#L97) | Releases presentation state after all drawing scopes and domain edit gestures have ended. | — | `System.InvalidOperationException`: A drawing scope is active or the caller is not the owner thread. | | [`public sealed class Inno.Editor.ImGui.ImGuiEditorRuntime : Inno.Editor.Core.EditorRuntime`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/ImGuiEditorRuntime.cs#L21) | Presents the backend-independent editor interaction runtime through ImGui. | — | — | -| [`public Inno.Editor.ImGui.ImGuiEditorRuntime.ImGuiEditorRuntime(Inno.Editor.Core.EditorContext context, Inno.Extensibility.Types.TypeCatalog types, Inno.Core.Logging.LogRouter logs, System.Collections.Generic.IEnumerable hostServices)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/ImGuiEditorRuntime.cs#L52) | Creates an ImGui editor runtime with stable host-owned extension services.
`context`: The shared editor context that owns project settings and frame state.
`types`: The host-owned type catalog that coordinates extension generations.
`logs`: The host-owned logging router used by editor infrastructure.
`hostServices`: Services available to discovered extension constructors. | — | `System.ArgumentNullException`: Thrown when , , or is . | +| [`public Inno.Editor.ImGui.ImGuiEditorRuntime.ImGuiEditorRuntime(Inno.Editor.Core.EditorContext context, Inno.Extensibility.Types.TypeCatalog types, Inno.Core.Logging.LogRouter logs, System.Collections.Generic.IEnumerable hostServices)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/ImGuiEditorRuntime.cs#L52) | Creates an ImGui editor runtime with stable host-owned extension services.
`context`: The shared editor context that owns project settings and frame state.
`types`: The host-owned type catalog that coordinates extension generations.
`logs`: The host-owned logging router used by editor infrastructure.
`hostServices`: Services available to discovered extension constructors. | — | `System.ArgumentNullException`: Thrown when context, types, or hostServices is null. | | [`public Inno.Editor.Interactions.EditorInteractions Inno.Editor.ImGui.ImGuiEditorRuntime.interactions { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/ImGuiEditorRuntime.cs#L75) | Gets the active presentation-independent interaction entry point. | — | — | | [`public int Inno.Editor.ImGui.ImGuiEditorRuntime.panelCount { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/ImGuiEditorRuntime.cs#L79) | Gets the number of active dockable panels. | — | — | | [`public override void Inno.Editor.ImGui.ImGuiEditorRuntime.Start()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/ImGuiEditorRuntime.cs#L84) | Starts value processing after validating the current state. | — | — | -| [`public override void Inno.Editor.ImGui.ImGuiEditorRuntime.Update(Inno.Editor.Core.EditorFrame frame)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/ImGuiEditorRuntime.cs#L96) | Recomputes owned state from the current validated inputs.
`frame`: The frame consumed by update; ownership remains with the caller unless explicitly stated otherwise. | — | — | +| [`public override void Inno.Editor.ImGui.ImGuiEditorRuntime.Update(Inno.Editor.Core.EditorFrame frame)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/ImGuiEditorRuntime.cs#L96) | Recomputes owned state from the current validated inputs.
`frame`: The frame consumed by update; ownership remains with the caller unless explicitly stated otherwise. | — | — | | [`public void Inno.Editor.ImGui.ImGuiEditorRuntime.SaveState()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/ImGuiEditorRuntime.cs#L108) | Captures all stateful active modules and panels and flushes their project state to disk. | — | `System.ObjectDisposedException`: Thrown after this runtime has been disposed. | | [`public void Inno.Editor.ImGui.ImGuiEditorRuntime.PrepareShutdown()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/ImGuiEditorRuntime.cs#L126) | Freezes automatic extension-state persistence and writes the final project state before editor modules begin shutting down. | — | `System.ObjectDisposedException`: Thrown after this runtime has been disposed. | | [`public void Inno.Editor.ImGui.ImGuiEditorRuntime.PrepareFrame()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/ImGuiEditorRuntime.cs#L143) | Applies pending style inputs with the owned context before the backend creates its native frame. | — | `System.ObjectDisposedException`: This runtime has retired.
`System.InvalidOperationException`: The owning native context is unavailable, incorrect, or already drawing. | | [`public void Inno.Editor.ImGui.ImGuiEditorRuntime.Draw()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/ImGuiEditorRuntime.cs#L154) | Draws the complete editor frame through ImGui. | — | — | -| [`public void Inno.Editor.ImGui.ImGuiEditorRuntime.HandleKeyPressed(Inno.Core.Events.KeyPressedEvent keyEvent)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/ImGuiEditorRuntime.cs#L281) | Dispatches contextual shortcuts, leaving editing keys with active text widgets while permitting explicit save.
`keyEvent`: The keyboard event received from the application event stream. | — | — | +| [`public void Inno.Editor.ImGui.ImGuiEditorRuntime.HandleKeyPressed(Inno.Core.Events.KeyPressedEvent keyEvent)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/ImGuiEditorRuntime.cs#L281) | Dispatches contextual shortcuts, leaving editing keys with active text widgets while permitting explicit save.
`keyEvent`: The keyboard event received from the application event stream. | — | — | | [`public override void Inno.Editor.ImGui.ImGuiEditorRuntime.Dispose()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/ImGuiEditorRuntime.cs#L302) | Releases the resources owned by this implementation. | — | `Inno.Core.Execution.RetirementPendingException`: Editor extensions still own live work. The interaction runtime remains retained for safe shutdown. | | [`public static class Inno.Editor.ImGui.EditorPalette`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L11) | Defines the complete editor color palette in one theme surface. | — | — | | [`public const float Inno.Editor.ImGui.EditorPalette.opacityNone = 0`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L16) | Gets zero opacity for invisible surfaces. | — | — | @@ -2343,15 +2402,15 @@ static void DrawHelp() | [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.contentTextMuted { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L366) | Gets the muted content text color. | — | — | | [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.contextText { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L371) | Gets the subdued contextual text color used by paths and origin hints. | — | — | | [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.contentAccent { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L376) | Gets the opaque content accent. | — | — | -| [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.GetHovered(System.Numerics.Vector4 color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L387) | Gets a hover treatment derived from a base theme color.
`color`: The color consumed by get hovered; ownership remains with the caller unless explicitly stated otherwise. | The base color blended toward the palette text color using the standard hover amount. | — | -| [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.GetActive(System.Numerics.Vector4 color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L398) | Gets an active treatment derived from a base theme color.
`color`: The color consumed by get active; ownership remains with the caller unless explicitly stated otherwise. | The base color blended toward the palette text color using the standard active amount. | — | +| [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.GetHovered(System.Numerics.Vector4 color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L387) | Gets a hover treatment derived from a base theme color.
`color`: The color consumed by get hovered; ownership remains with the caller unless explicitly stated otherwise. | The base color blended toward the palette text color using the standard hover amount. | — | +| [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.GetActive(System.Numerics.Vector4 color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L398) | Gets an active treatment derived from a base theme color.
`color`: The color consumed by get active; ownership remains with the caller unless explicitly stated otherwise. | The base color blended toward the palette text color using the standard active amount. | — | | [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.treeGuide { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L403) | Gets the guide color of reusable tree controls. | — | — | | [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.axisX { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L408) | Gets X axis color. | — | — | | [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.axisY { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L413) | Gets Y axis color. | — | — | | [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.axisZ { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L418) | Gets Z axis color. | — | — | | [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.axisW { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L423) | Gets W axis color. | — | — | -| [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.Lerp(System.Numerics.Vector4 from, System.Numerics.Vector4 to, float amount)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L440) | Linearly interpolates two palette colors using a clamped amount.
`from`: The color returned when is zero.
`to`: The color returned when is one.
`amount`: The interpolation amount, clamped to the inclusive zero-to-one range. | The component-wise interpolated color. | — | -| [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.WithOpacity(System.Numerics.Vector4 color, float opacity)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L523) | Returns a theme color with a caller-selected opacity, normally one of the shared opacity levels.
`color`: Base RGB color.
`opacity`: Replacement alpha in the inclusive zero-to-one range. | The validated vector4 that represents the completed operation. | — | +| [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.Lerp(System.Numerics.Vector4 from, System.Numerics.Vector4 to, float amount)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L440) | Linearly interpolates two palette colors using a clamped amount.
`from`: The color returned when amount is zero.
`to`: The color returned when amount is one.
`amount`: The interpolation amount, clamped to the inclusive zero-to-one range. | The component-wise interpolated color. | — | +| [`public static System.Numerics.Vector4 Inno.Editor.ImGui.EditorPalette.WithOpacity(System.Numerics.Vector4 color, float opacity)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorPalette.cs#L523) | Returns a theme color with a caller-selected opacity, normally one of the shared opacity levels.
`color`: Base RGB color.
`opacity`: Replacement alpha in the inclusive zero-to-one range. | The validated vector4 that represents the completed operation. | — | | [`public sealed class Inno.Editor.ImGui.EditorStyleMetrics`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L14) | Defines reusable layout metrics and separates owned frame values from requested style changes. | — | — | | [`public const float Inno.Editor.ImGui.EditorStyleMetrics.C_MIN_ZOOM = 0.75`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L19) | Defines the smallest supported editor UI zoom. | — | — | | [`public const float Inno.Editor.ImGui.EditorStyleMetrics.C_MAX_ZOOM = 1.5`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L24) | Defines the largest supported editor UI zoom. | — | — | @@ -2360,11 +2419,11 @@ static void DrawHelp() | [`public float Inno.Editor.ImGui.EditorStyleMetrics.zoom { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L51) | Gets the effective zoom used by the current presentation frame. | — | — | | [`public bool Inno.Editor.ImGui.EditorStyleMetrics.isCompact { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L56) | Gets whether compact editor density is active. | — | — | | [`public float Inno.Editor.ImGui.EditorStyleMetrics.trendHeight { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L61) | Gets the scaled height of a compact sampled-value trend plot. | — | — | -| [`public bool Inno.Editor.ImGui.EditorStyleMetrics.SetCompactMode(bool value)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L78) | Requests comfortable or compact density without changing an active session frame.
`value`: for compact density. | when the requested density changed; owned drawing applies it at the next frame preparation. | `System.ObjectDisposedException`: The owning session has retired or is no longer available.
`System.InvalidOperationException`: The caller is not the owning session's thread. | -| [`public bool Inno.Editor.ImGui.EditorStyleMetrics.SetZoom(float value)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L106) | Requests a bounded zoom without changing metrics partway through an owned native frame.
`value`: The requested UI zoom multiplier. | when the requested zoom changed; owned drawing applies it at the next frame preparation. | `System.ArgumentOutOfRangeException`: Thrown when is not finite.
`System.ObjectDisposedException`: The owning session has retired or is no longer available.
`System.InvalidOperationException`: The caller is not the owning session's thread. | -| [`public bool Inno.Editor.ImGui.EditorStyleMetrics.ZoomIn()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L125) | Increases editor UI zoom by one bounded increment. | when the requested zoom changed. | — | -| [`public bool Inno.Editor.ImGui.EditorStyleMetrics.ZoomOut()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L133) | Decreases editor UI zoom by one bounded increment. | when the requested zoom changed. | — | -| [`public bool Inno.Editor.ImGui.EditorStyleMetrics.ResetZoom()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L141) | Restores the baseline editor UI zoom. | when the requested zoom changed. | — | +| [`public bool Inno.Editor.ImGui.EditorStyleMetrics.SetCompactMode(bool value)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L78) | Requests comfortable or compact density without changing an active session frame.
`value`: true for compact density. | true when the requested density changed; owned drawing applies it at the next frame preparation. | `System.ObjectDisposedException`: The owning session has retired or is no longer available.
`System.InvalidOperationException`: The caller is not the owning session's thread. | +| [`public bool Inno.Editor.ImGui.EditorStyleMetrics.SetZoom(float value)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L106) | Requests a bounded zoom without changing metrics partway through an owned native frame.
`value`: The requested UI zoom multiplier. | true when the requested zoom changed; owned drawing applies it at the next frame preparation. | `System.ArgumentOutOfRangeException`: Thrown when value is not finite.
`System.ObjectDisposedException`: The owning session has retired or is no longer available.
`System.InvalidOperationException`: The caller is not the owning session's thread. | +| [`public bool Inno.Editor.ImGui.EditorStyleMetrics.ZoomIn()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L125) | Increases editor UI zoom by one bounded increment. | true when the requested zoom changed. | — | +| [`public bool Inno.Editor.ImGui.EditorStyleMetrics.ZoomOut()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L133) | Decreases editor UI zoom by one bounded increment. | true when the requested zoom changed. | — | +| [`public bool Inno.Editor.ImGui.EditorStyleMetrics.ResetZoom()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L141) | Restores the baseline editor UI zoom. | true when the requested zoom changed. | — | | [`public float Inno.Editor.ImGui.EditorStyleMetrics.fontScale { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L146) | Gets global content scale. | — | — | | [`public float Inno.Editor.ImGui.EditorStyleMetrics.disabledAlpha { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L151) | Gets disabled content opacity. | — | — | | [`public System.Numerics.Vector2 Inno.Editor.ImGui.EditorStyleMetrics.windowPadding { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L156) | Gets standard window padding. | — | — | @@ -2428,15 +2487,14 @@ static void DrawHelp() | [`public float Inno.Editor.ImGui.EditorStyleMetrics.axisPrefixMinimumWidth { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L447) | Gets the minimum width of an axis prefix. | — | — | | [`public float Inno.Editor.ImGui.EditorStyleMetrics.axisPrefixWidthRatio { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L452) | Gets the axis prefix share of the complete control. | — | — | | [`public float Inno.Editor.ImGui.EditorStyleMetrics.interactionOverlayThickness { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L457) | Gets the standard foreground interaction-overlay thickness. | — | — | -| [`public float Inno.Editor.ImGui.EditorStyleMetrics.scriptCompilationWidth { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L462) | Gets script compilation modal width. | — | — | -| [`public float Inno.Editor.ImGui.EditorStyleMetrics.modalWidth { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L467) | Gets the standard centered modal width. | — | — | -| [`public double Inno.Editor.ImGui.EditorStyleMetrics.modalFadeInSeconds { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L472) | Gets the modal fade-in duration in seconds. | — | — | -| [`public double Inno.Editor.ImGui.EditorStyleMetrics.modalMinimumVisibleSeconds { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L477) | Gets the minimum modal visibility duration in seconds. | — | — | -| [`public double Inno.Editor.ImGui.EditorStyleMetrics.modalFadeOutSeconds { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L482) | Gets the modal fade-out duration in seconds. | — | — | -| [`public float Inno.Editor.ImGui.EditorStyleMetrics.treeGuideLeftOffset { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L487) | Gets tree guide left offset. | — | — | -| [`public float Inno.Editor.ImGui.EditorStyleMetrics.treeGuideLineOverlap { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L492) | Gets the overlap used to join adjacent tree guide segments. | — | — | -| [`public float Inno.Editor.ImGui.EditorStyleMetrics.treeFolderConnectorPadding { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L497) | Gets additional connector padding for expandable tree nodes. | — | — | -| [`public float Inno.Editor.ImGui.EditorStyleMetrics.textDecorationOffset { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L502) | Gets the vertical offset of text decorations from the baseline. | — | — | +| [`public float Inno.Editor.ImGui.EditorStyleMetrics.modalWidth { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L462) | Gets the standard centered modal width. | — | — | +| [`public double Inno.Editor.ImGui.EditorStyleMetrics.modalFadeInSeconds { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L467) | Gets the modal fade-in duration in seconds. | — | — | +| [`public double Inno.Editor.ImGui.EditorStyleMetrics.modalMinimumVisibleSeconds { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L472) | Gets the minimum modal visibility duration in seconds. | — | — | +| [`public double Inno.Editor.ImGui.EditorStyleMetrics.modalFadeOutSeconds { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L477) | Gets the modal fade-out duration in seconds. | — | — | +| [`public float Inno.Editor.ImGui.EditorStyleMetrics.treeGuideLeftOffset { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L482) | Gets tree guide left offset. | — | — | +| [`public float Inno.Editor.ImGui.EditorStyleMetrics.treeGuideLineOverlap { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L487) | Gets the overlap used to join adjacent tree guide segments. | — | — | +| [`public float Inno.Editor.ImGui.EditorStyleMetrics.treeFolderConnectorPadding { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L492) | Gets additional connector padding for expandable tree nodes. | — | — | +| [`public float Inno.Editor.ImGui.EditorStyleMetrics.textDecorationOffset { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs#L497) | Gets the vertical offset of text decorations from the baseline. | — | — | | [`public readonly struct Inno.Editor.ImGui.EditorUiLayout`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorUiLayout.cs#L8) | Copies the presentation metrics needed by custom layouts without retaining native style memory. | — | — | | [`public System.Numerics.Vector2 Inno.Editor.ImGui.EditorUiLayout.itemSpacing { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorUiLayout.cs#L13) | Gets spacing between neighboring controls. | — | — | | [`public System.Numerics.Vector2 Inno.Editor.ImGui.EditorUiLayout.windowPadding { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorUiLayout.cs#L17) | Gets the current window inset. | — | — | @@ -2453,8 +2511,8 @@ static void DrawHelp() | [`Inno.Editor.ImGui.ImGuiFontStyle.Bold = 1`](../../src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiFont.cs#L20) | Emphasizes text with the bold face. | — | — | | [`Inno.Editor.ImGui.ImGuiFontStyle.Italic = 2`](../../src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiFont.cs#L24) | Emphasizes text with the italic face. | — | — | | [`public static class Inno.Editor.ImGui.ImGuiFont`](../../src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiFont.cs#L30) | Uses the host's context-owned font catalog without exposing backend types to Editor features. | — | — | -| [`public static bool Inno.Editor.ImGui.ImGuiFont.IsAvailable(Inno.Editor.ImGui.ImGuiFontStyle style)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiFont.cs#L41) | Checks whether the current host registered an exact face.
`style`: The requested emphasis. | True when the exact face is available. | — | -| [`public static Inno.Editor.ImGui.ImGuiFontScope Inno.Editor.ImGui.ImGuiFont.PushStyle(Inno.Editor.ImGui.ImGuiFontStyle style)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiFont.cs#L56) | Pushes a host-owned font face for one synchronous control group.
`style`: The requested emphasis. | An owner-window/frame scope; the host may use a registered nearest face. | — | +| [`public static bool Inno.Editor.ImGui.ImGuiFont.IsAvailable(Inno.Editor.ImGui.ImGuiFontStyle style)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiFont.cs#L41) | Checks whether the current host registered an exact face.
`style`: The requested emphasis. | True when the exact face is available. | — | +| [`public static Inno.Editor.ImGui.ImGuiFontScope Inno.Editor.ImGui.ImGuiFont.PushStyle(Inno.Editor.ImGui.ImGuiFontStyle style)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiFont.cs#L56) | Pushes a host-owned font face for one synchronous control group.
`style`: The requested emphasis. | An owner-window/frame scope; the host may use a registered nearest face. | — | | [`public ref struct Inno.Editor.ImGui.ImGuiFontScope : System.IDisposable`](../../src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiFont.cs#L68) | Restores a font push only in its original session, frame and native stack position. | — | — | | [`public void Inno.Editor.ImGui.ImGuiFontScope.Dispose()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiFont.cs#L92) | Restores the preceding font after validating scope order; default and retired scopes are inert. | — | `System.InvalidOperationException`: The scope is used in another context, frame or stack position. | | [`public static class Inno.Editor.ImGui.ImGuiIcon`](../../src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiIcon.cs#L5) | Provides the standard Editor glyph vocabulary; extension controls may also supply their own glyph text. | — | — | @@ -2502,99 +2560,120 @@ static void DrawHelp() | [`public const string Inno.Editor.ImGui.ImGuiIcon.VectorSquare = ""`](../../src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiIcon.cs#L174) | Gets the vector square glyph used by standard Editor controls. | — | — | | [`public const string Inno.Editor.ImGui.ImGuiIcon.Xmark = ""`](../../src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiIcon.cs#L178) | Gets the xmark glyph used by standard Editor controls. | — | — | | [`public sealed class Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Card.cs#L10) | Provides reusable editor controls and rendering helpers built on the native ImGui API. | — | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CollapsingCard(string id, string title, System.Action? drawLeadingControl = null, System.Action? drawTrailingControl = null, bool defaultOpen = true, bool dimmed = false, float trailingControlWidth = 0, System.Action? drawContextMenu = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Card.cs#L42) | Draws a component-style collapsible card header.
`id`: The stable card identifier.
`title`: The visible card title.
`drawLeadingControl`: An optional control drawn before the title.
`drawTrailingControl`: An optional control aligned to the right edge.
`defaultOpen`: Whether the card starts expanded.
`dimmed`: Whether header controls and title use the inactive text color.
`trailingControlWidth`: The optional width reserved for the trailing control group.
`drawContextMenu`: An optional callback that binds a context menu to the complete header item. | when card content should be drawn; otherwise, . | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DrawDisclosureIndicator(System.Numerics.Vector2 min, System.Numerics.Vector2 max, bool open, bool dimmed = false)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Card.cs#L195) | Draws a vertically centered disclosure triangle with button-style hover feedback.
`min`: The minimum screen coordinate of the indicator area.
`max`: The maximum screen coordinate of the indicator area.
`open`: Whether the represented content is expanded.
`dimmed`: Whether the indicator uses the inactive text color. | — | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CardBody(string id, System.Action drawContent, bool dimmed = false)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Card.cs#L238) | Draws expanded collapsible-card content inside a framed body.
`id`: The stable card identifier.
`drawContent`: The callback that draws card content.
`dimmed`: Whether content is visually disabled and non-interactive. | — | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.ClippedRows(int itemCount, float itemHeight, TState state, System.Action drawRange, System.ReadOnlySpan preservedRows = default(System.ReadOnlySpan))`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Clipping.cs#L42) | Draws visible row ranges and preserves native scrolling, navigation and table cursor bookkeeping.
`itemCount`: The nonnegative count in the caller's current filtered and sorted view.
`itemHeight`: The complete fixed row advance in screen pixels, or -1 to measure the first row through the native clipper.
`state`: Data borrowed only for this call; it is never stored by the widget.
`drawRange`: A synchronous drawing callback receiving inclusive start and exclusive end indices.
`preservedRows`: Optional rows that must still submit an active edit, drag source or requested focus.
`TState`: Call-scoped drawing data, passed directly so static callbacks need no captured closure. | — | `System.ArgumentNullException`: The drawing callback is null.
`System.ArgumentOutOfRangeException`: A count, row height or preserved index is invalid.
`System.InvalidOperationException`: No native frame is active in this UI session. | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginMenuPopup(string id)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L31) | Begins an explicitly opened popup using the editor context-menu presentation contract. The popup stays in its parent viewport, sizes itself to submitted content, and scrolls when its work-area bound is reached.
`id`: The stable identifier previously passed to ImGui when opening the popup. | when popup content should be submitted; otherwise, . | `System.ArgumentException`: Thrown when is empty. | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.EndMenuPopup()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L47) | Ends a popup opened by and restores the previous style. | — | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginMenuTooltip()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L61) | Begins a parent-viewport tooltip using the same padding, colors, border, and spacing as editor menus. | when tooltip content should be submitted; otherwise, . | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.EndMenuTooltip()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L75) | Ends a tooltip opened by and restores the previous style. | — | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DrawItemTooltip(string? text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L88) | Draws a consistently sized, wrapped editor tooltip for the most recently submitted item.
`text`: Tooltip text. Empty values do not draw a tooltip. | — | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DrawTooltip(string? text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L105) | Draws the standard viewport-clamped tooltip when a custom-drawn canvas element is hovered.
`text`: Tooltip contents. The caller owns hit testing; empty text draws nothing. | — | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginContextMenu(string id)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L161) | Begins a parent-viewport styled right-click context menu for the most recently submitted item.
`id`: The stable popup identifier in the current ImGui ID scope. | when context-menu content should be drawn; otherwise, . | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginWindowContextMenu(string id)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L183) | Begins a parent-viewport styled right-click context menu for the current window's unoccupied background.
`id`: The stable popup identifier in the current ImGui ID scope. | when context-menu content should be drawn; otherwise, . | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.EndContextMenu()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L202) | Ends a context menu opened by or . | — | — | -| [`public System.Numerics.Vector2 Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.GetLabelChipSize(string label)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L24) | Gets the layout size of a compact colored label chip using the centralized editor style.
`label`: Visible label text. | The size reserved by for the supplied text. | `System.ArgumentNullException`: Thrown when is . | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.LabelChip(string label, System.Numerics.Vector4 background)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L44) | Draws non-interactive text centered on a compact, softly rounded colored background.
`label`: Visible label text.
`background`: Background color drawn behind the label. | — | `System.ArgumentNullException`: Thrown when is . | -| [`public System.Numerics.Vector2 Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.GetTypeBadgeSize(string label)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L71) | Gets the layout size of a compact outlined type badge.
`label`: Visible type name. | The size reserved by . | `System.ArgumentNullException`: Thrown when is . | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.TypeBadge(string label, System.Numerics.Vector4 accent, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L94) | Draws a compact, non-interactive type badge with a subdued fill and semantic outline.
`label`: Visible type name.
`accent`: Semantic type-family accent.
`tooltip`: Optional explanation shown while the badge is hovered. | — | `System.ArgumentNullException`: Thrown when is . | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CompactCheckbox(string id, ref bool value, float size = -1, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L134) | Draws a compact checkbox whose checked fill uses the current text color.
`id`: Stable control identifier.
`value`: Mutable checked state.
`size`: Visual square size in pixels.
`tooltip`: Optional explanation displayed while the checkbox is hovered. | when the value changed. | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.Checkbox(string label, ref bool value, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L202) | Draws a standard checkbox with the shared editor tooltip behavior.
`label`: Visible label and stable ImGui identifier.
`value`: Mutable checked state.
`tooltip`: Optional explanation displayed while the checkbox is hovered. | when the value changed. | `System.ArgumentException`: Thrown when is empty or whitespace. | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CenteredButton(string label, float topPadding = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L226) | Draws a horizontally centered button with optional space above it.
`label`: Visible label and optional ImGui identifier suffix.
`topPadding`: Additional vertical space above the button. | when the button is pressed. | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CenteredProgressBar(float fraction, System.Numerics.Vector2 size, string overlay)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L263) | Draws a progress bar whose overlay remains centered over the complete bar.
`fraction`: The completed fraction rendered by the progress bar.
`size`: The requested ImGui progress-bar size.
`overlay`: The text drawn at the geometric center of the complete progress bar. | — | `System.ArgumentNullException`: Thrown when is . | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DragDropSource(string payloadType, in TPayload payload, System.Action? drawPreview = null, bool allowHoldToOpenOthers = true) where TPayload : unmanaged`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.DragDrop.cs#L37) | Publishes an unmanaged drag payload for the most recently submitted item.
`payloadType`: Stable ImGui payload type identifier.
`payload`: Payload value.
`drawPreview`: Optional preview drawing callback.
`allowHoldToOpenOthers`: Whether hovering over another openable control may open it after the native drag-hold delay.
`TPayload`: Unmanaged payload type. | while the item is an active drag source. | `System.ArgumentException`: Thrown when is empty or whitespace. | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DragDropSource(string payloadType, System.Func payloadFactory, System.Action? drawPreview = null, bool allowHoldToOpenOthers = true) where TPayload : unmanaged`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.DragDrop.cs#L85) | Publishes a lazily created unmanaged drag payload for the most recently submitted item.
`payloadType`: Stable ImGui payload type identifier.
`payloadFactory`: Creates the payload only after dragging starts.
`drawPreview`: Optional preview drawing callback.
`allowHoldToOpenOthers`: Whether hovering over another openable control may open it after the native drag-hold delay.
`TPayload`: Unmanaged payload type. | while the item is an active drag source. | `System.ArgumentException`: Thrown when is empty or whitespace.
`System.ArgumentNullException`: Thrown when is . | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DragDropTarget(string payloadType, out TPayload payload) where TPayload : unmanaged`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.DragDrop.cs#L123) | Accepts an unmanaged payload on the most recently submitted item.
`payloadType`: Stable ImGui payload type identifier.
`payload`: Delivered payload value.
`TPayload`: Unmanaged payload type. | only when a compatible payload is delivered. | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DragDropTarget(string payloadType, out TPayload payload, out bool isPreviewing) where TPayload : unmanaged`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.DragDrop.cs#L150) | Accepts an unmanaged payload and reports its preview state on the most recently submitted item.
`payloadType`: Stable ImGui payload type identifier.
`payload`: Previewed or delivered payload value.
`isPreviewing`: Whether a compatible payload is hovering over the target.
`TPayload`: Unmanaged payload type. | only when a compatible payload is delivered. | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DragDropTarget(string payloadType, out TPayload payload, out bool isPreviewing, bool drawDefaultHighlight) where TPayload : unmanaged`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.DragDrop.cs#L181) | Accepts an unmanaged payload and controls whether ImGui draws its default target rectangle.
`payloadType`: Stable ImGui payload type identifier.
`payload`: Previewed or delivered payload value.
`isPreviewing`: Whether a compatible payload is hovering over the target.
`drawDefaultHighlight`: Whether ImGui draws its default target rectangle.
`TPayload`: Unmanaged payload type. | only when a compatible payload is delivered. | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DragDropTarget(string payloadType, System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, uint targetId, out TPayload payload, out bool isPreviewing, bool drawDefaultHighlight = true) where TPayload : unmanaged`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.DragDrop.cs#L243) | Accepts an unmanaged payload on an explicit screen-space rectangle.
`payloadType`: Stable ImGui payload type identifier.
`minimum`: Minimum screen coordinate of the complete target.
`maximum`: Maximum screen coordinate of the complete target.
`targetId`: ImGui identifier unique within the current window.
`payload`: Previewed or delivered payload value.
`isPreviewing`: Whether a compatible payload is hovering over the target.
`drawDefaultHighlight`: Whether ImGui draws its default target rectangle.
`TPayload`: Unmanaged payload type. | only when a compatible payload is delivered. | `System.ArgumentException`: Thrown when is empty or whitespace. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CollapsingCard(string id, string title, System.Action? drawLeadingControl = null, System.Action? drawTrailingControl = null, bool defaultOpen = true, bool dimmed = false, float trailingControlWidth = 0, System.Action? drawContextMenu = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Card.cs#L42) | Draws a component-style collapsible card header.
`id`: The stable card identifier.
`title`: The visible card title.
`drawLeadingControl`: An optional control drawn before the title.
`drawTrailingControl`: An optional control aligned to the right edge.
`defaultOpen`: Whether the card starts expanded.
`dimmed`: Whether header controls and title use the inactive text color.
`trailingControlWidth`: The optional width reserved for the trailing control group.
`drawContextMenu`: An optional callback that binds a context menu to the complete header item. | true when card content should be drawn; otherwise, false. | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DrawDisclosureIndicator(System.Numerics.Vector2 min, System.Numerics.Vector2 max, bool open, bool dimmed = false)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Card.cs#L195) | Draws a vertically centered disclosure triangle with button-style hover feedback.
`min`: The minimum screen coordinate of the indicator area.
`max`: The maximum screen coordinate of the indicator area.
`open`: Whether the represented content is expanded.
`dimmed`: Whether the indicator uses the inactive text color. | — | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CardBody(string id, System.Action drawContent, bool dimmed = false)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Card.cs#L238) | Draws expanded collapsible-card content inside a framed body.
`id`: The stable card identifier.
`drawContent`: The callback that draws card content.
`dimmed`: Whether content is visually disabled and non-interactive. | — | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.ClippedRows(int itemCount, float itemHeight, TState state, System.Action drawRange, System.ReadOnlySpan preservedRows = default(System.ReadOnlySpan))`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Clipping.cs#L42) | Draws visible row ranges and preserves native scrolling, navigation and table cursor bookkeeping.
`TState`: Call-scoped drawing data, passed directly so static callbacks need no captured closure.
`itemCount`: The nonnegative count in the caller's current filtered and sorted view.
`itemHeight`: The complete fixed row advance in screen pixels, or -1 to measure the first row through the native clipper.
`state`: Data borrowed only for this call; it is never stored by the widget.
`drawRange`: A synchronous drawing callback receiving inclusive start and exclusive end indices.
`preservedRows`: Optional rows that must still submit an active edit, drag source or requested focus. | — | `System.ArgumentNullException`: The drawing callback is null.
`System.ArgumentOutOfRangeException`: A count, row height or preserved index is invalid.
`System.InvalidOperationException`: No native frame is active in this UI session. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginMenuPopup(string id)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L31) | Begins an explicitly opened popup using the editor context-menu presentation contract. The popup stays in its parent viewport, sizes itself to submitted content, and scrolls when its work-area bound is reached.
`id`: The stable identifier previously passed to ImGui when opening the popup. | true when popup content should be submitted; otherwise, false. | `System.ArgumentException`: Thrown when id is empty. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.EndMenuPopup()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L47) | Ends a popup opened by Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginMenuPopup(System.String) and restores the previous style. | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginMenuTooltip()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L61) | Begins a parent-viewport tooltip using the same padding, colors, border, and spacing as editor menus. | true when tooltip content should be submitted; otherwise, false. | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.EndMenuTooltip()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L75) | Ends a tooltip opened by Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginMenuTooltip and restores the previous style. | — | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DrawItemTooltip(string? text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L88) | Draws a consistently sized, wrapped editor tooltip for the most recently submitted item.
`text`: Tooltip text. Empty values do not draw a tooltip. | — | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DrawTooltip(string? text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L105) | Draws the standard viewport-clamped tooltip when a custom-drawn canvas element is hovered.
`text`: Tooltip contents. The caller owns hit testing; empty text draws nothing. | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginContextMenu(string id)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L161) | Begins a parent-viewport styled right-click context menu for the most recently submitted item.
`id`: The stable popup identifier in the current ImGui ID scope. | true when context-menu content should be drawn; otherwise, false. | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginWindowContextMenu(string id)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L183) | Begins a parent-viewport styled right-click context menu for the current window's unoccupied background.
`id`: The stable popup identifier in the current ImGui ID scope. | true when context-menu content should be drawn; otherwise, false. | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.EndContextMenu()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.ContextMenu.cs#L202) | Ends a context menu opened by Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginContextMenu(System.String) or Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginWindowContextMenu(System.String). | — | — | +| [`public System.Numerics.Vector2 Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.GetLabelChipSize(string label)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L24) | Gets the layout size of a compact colored label chip using the centralized editor style.
`label`: Visible label text. | The size reserved by Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.LabelChip(System.String,System.Numerics.Vector4) for the supplied text. | `System.ArgumentNullException`: Thrown when label is null. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.LabelChip(string label, System.Numerics.Vector4 background)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L44) | Draws non-interactive text centered on a compact, softly rounded colored background.
`label`: Visible label text.
`background`: Background color drawn behind the label. | — | `System.ArgumentNullException`: Thrown when label is null. | +| [`public System.Numerics.Vector2 Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.GetTypeBadgeSize(string label)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L71) | Gets the layout size of a compact outlined type badge.
`label`: Visible type name. | The size reserved by Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.TypeBadge(System.String,System.Numerics.Vector4,System.String). | `System.ArgumentNullException`: Thrown when label is null. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.TypeBadge(string label, System.Numerics.Vector4 accent, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L94) | Draws a compact, non-interactive type badge with a subdued fill and semantic outline.
`label`: Visible type name.
`accent`: Semantic type-family accent.
`tooltip`: Optional explanation shown while the badge is hovered. | — | `System.ArgumentNullException`: Thrown when label is null. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CompactCheckbox(string id, ref bool value, float size = -1, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L134) | Draws a compact checkbox whose checked fill uses the current text color.
`id`: Stable control identifier.
`value`: Mutable checked state.
`size`: Visual square size in pixels.
`tooltip`: Optional explanation displayed while the checkbox is hovered. | true when the value changed. | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.Checkbox(string label, ref bool value, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L202) | Draws a standard checkbox with the shared editor tooltip behavior.
`label`: Visible label and stable ImGui identifier.
`value`: Mutable checked state.
`tooltip`: Optional explanation displayed while the checkbox is hovered. | true when the value changed. | `System.ArgumentException`: Thrown when label is empty or whitespace. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CenteredButton(string label, float topPadding = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L226) | Draws a horizontally centered button with optional space above it.
`label`: Visible label and optional ImGui identifier suffix.
`topPadding`: Additional vertical space above the button. | true when the button is pressed. | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CenteredProgressBar(float fraction, System.Numerics.Vector2 size, string overlay)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs#L263) | Draws a progress bar whose overlay remains centered over the complete bar.
`fraction`: The completed fraction rendered by the progress bar.
`size`: The requested ImGui progress-bar size.
`overlay`: The text drawn at the geometric center of the complete progress bar. | — | `System.ArgumentNullException`: Thrown when overlay is null. | +| [`public Inno.Editor.ImGui.ImGuiWidget.DialogLayout Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.MeasureDialog(Inno.Editor.ImGui.ImGuiWidget.DialogPresentation presentation, System.Numerics.Vector2 availableSize)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L101) | Measures current dialog content before its window is opened. The returned geometry must be used with the same presentation.
`presentation`: The immutable content captured for this frame.
`availableSize`: The bounded content area in already scaled presentation coordinates. | The bounded current-frame layout, including a single scrolling body when required. | `System.ArgumentNullException`: The message is null.
`System.ArgumentOutOfRangeException`: The available dimensions are not finite and positive, or a determinate progress fraction is outside zero through one.
`System.InvalidOperationException`: The owning frame, context or thread is not active.
`System.ObjectDisposedException`: The owning UI session has retired. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DrawDialog(Inno.Editor.ImGui.ImGuiWidget.DialogPresentation presentation, Inno.Editor.ImGui.ImGuiWidget.DialogLayout layout)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L154) | Draws one prepared message dialog. Text owns one bounded scroll region and actions remain outside it.
`presentation`: The same immutable content used for measurement.
`layout`: The measurement captured in this frame and context. | True when the enabled action was activated by native button input or its explicitly enabled Escape policy. | `System.ArgumentNullException`: The message is null.
`System.ArgumentOutOfRangeException`: The layout is invalid.
`System.InvalidOperationException`: The owning frame, context or thread is not active.
`System.ObjectDisposedException`: The owning UI session has retired. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DragDropSource(string payloadType, in TPayload payload, System.Action? drawPreview = null, bool allowHoldToOpenOthers = true) where TPayload : unmanaged`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.DragDrop.cs#L37) | Publishes an unmanaged drag payload for the most recently submitted item.
`TPayload`: Unmanaged payload type.
`payloadType`: Stable ImGui payload type identifier.
`payload`: Payload value.
`drawPreview`: Optional preview drawing callback.
`allowHoldToOpenOthers`: Whether hovering over another openable control may open it after the native drag-hold delay. | true while the item is an active drag source. | `System.ArgumentException`: Thrown when payloadType is empty or whitespace. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DragDropSource(string payloadType, System.Func payloadFactory, System.Action? drawPreview = null, bool allowHoldToOpenOthers = true) where TPayload : unmanaged`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.DragDrop.cs#L85) | Publishes a lazily created unmanaged drag payload for the most recently submitted item.
`TPayload`: Unmanaged payload type.
`payloadType`: Stable ImGui payload type identifier.
`payloadFactory`: Creates the payload only after dragging starts.
`drawPreview`: Optional preview drawing callback.
`allowHoldToOpenOthers`: Whether hovering over another openable control may open it after the native drag-hold delay. | true while the item is an active drag source. | `System.ArgumentException`: Thrown when payloadType is empty or whitespace.
`System.ArgumentNullException`: Thrown when payloadFactory is null. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DragDropTarget(string payloadType, out TPayload payload) where TPayload : unmanaged`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.DragDrop.cs#L123) | Accepts an unmanaged payload on the most recently submitted item.
`TPayload`: Unmanaged payload type.
`payloadType`: Stable ImGui payload type identifier.
`payload`: Delivered payload value. | true only when a compatible payload is delivered. | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DragDropTarget(string payloadType, out TPayload payload, out bool isPreviewing) where TPayload : unmanaged`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.DragDrop.cs#L150) | Accepts an unmanaged payload and reports its preview state on the most recently submitted item.
`TPayload`: Unmanaged payload type.
`payloadType`: Stable ImGui payload type identifier.
`payload`: Previewed or delivered payload value.
`isPreviewing`: Whether a compatible payload is hovering over the target. | true only when a compatible payload is delivered. | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DragDropTarget(string payloadType, out TPayload payload, out bool isPreviewing, bool drawDefaultHighlight) where TPayload : unmanaged`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.DragDrop.cs#L181) | Accepts an unmanaged payload and controls whether ImGui draws its default target rectangle.
`TPayload`: Unmanaged payload type.
`payloadType`: Stable ImGui payload type identifier.
`payload`: Previewed or delivered payload value.
`isPreviewing`: Whether a compatible payload is hovering over the target.
`drawDefaultHighlight`: Whether ImGui draws its default target rectangle. | true only when a compatible payload is delivered. | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DragDropTarget(string payloadType, System.Numerics.Vector2 minimum, System.Numerics.Vector2 maximum, uint targetId, out TPayload payload, out bool isPreviewing, bool drawDefaultHighlight = true) where TPayload : unmanaged`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.DragDrop.cs#L243) | Accepts an unmanaged payload on an explicit screen-space rectangle.
`TPayload`: Unmanaged payload type.
`payloadType`: Stable ImGui payload type identifier.
`minimum`: Minimum screen coordinate of the complete target.
`maximum`: Maximum screen coordinate of the complete target.
`targetId`: ImGui identifier unique within the current window.
`payload`: Previewed or delivered payload value.
`isPreviewing`: Whether a compatible payload is hovering over the target.
`drawDefaultHighlight`: Whether ImGui draws its default target rectangle. | true only when a compatible payload is delivered. | `System.ArgumentException`: Thrown when payloadType is empty or whitespace. | | [`public string? Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.editMergeKey { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Editing.cs#L20) | Gets the current continuous-edit merge boundary, or null for a discrete edit. | — | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginPropertyEdit(Inno.Editor.Interactions.IEditorHistory history, string path, string name)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Editing.cs#L38) | Starts a History boundary only when a changed control is actively producing continuous input.
`history`: The authoritative domain History receiving the control's existing mutation records.
`path`: The stable owner-qualified property path.
`name`: The operation name shown by Undo and Redo. | — | `System.InvalidOperationException`: A previous gesture cannot complete or History rejects the transaction. | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginEdit(Inno.Editor.Interactions.IEditorHistory history, string path, string name)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Editing.cs#L62) | Begins or touches an explicitly captured continuous edit, such as a viewport manipulation.
`history`: The authoritative domain History.
`path`: The stable owner-qualified edit identity.
`name`: The user-facing Undo name. | — | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.IsEditing(string path)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Editing.cs#L92) | Checks whether this owner still owns a particular edit, including after a close or generation boundary.
`path`: The stable edit identity. | True only while the matching owner still has an active transaction. | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CompletePropertyEdit(string path)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Editing.cs#L100) | Observes the current property after drawing, including release and cancellation without a new value sample.
`path`: The owner-qualified path passed to the property edit boundary. | — | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginPropertyEdit(Inno.Editor.Interactions.IEditorHistory history, string path, string name)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Editing.cs#L38) | Starts a History boundary only when a changed control is actively producing continuous input.
`history`: The authoritative domain History receiving the control's existing mutation records.
`path`: The stable owner-qualified property path.
`name`: The operation name shown by Undo and Redo. | — | `System.InvalidOperationException`: A previous gesture cannot complete or History rejects the transaction. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginEdit(Inno.Editor.Interactions.IEditorHistory history, string path, string name)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Editing.cs#L62) | Begins or touches an explicitly captured continuous edit, such as a viewport manipulation.
`history`: The authoritative domain History.
`path`: The stable owner-qualified edit identity.
`name`: The user-facing Undo name. | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.IsEditing(string path)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Editing.cs#L92) | Checks whether this owner still owns a particular edit, including after a close or generation boundary.
`path`: The stable edit identity. | True only while the matching owner still has an active transaction. | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CompletePropertyEdit(string path)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Editing.cs#L100) | Observes the current property after drawing, including release and cancellation without a new value sample.
`path`: The owner-qualified path passed to the property edit boundary. | — | — | | [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CommitEdits()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Editing.cs#L119) | Completes the current control edit before a document command, reload, Play transition or shutdown. | — | `System.InvalidOperationException`: A nested transaction prevents completion; ownership is retained. | | [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CancelEdits()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Editing.cs#L135) | Restores the control's initial domain values before discarding its transient presentation state. | — | `System.InvalidOperationException`: Rollback is unavailable; the gesture remains owned for recovery. | -| [`public Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.TransformGizmo(Inno.Core.Mathematics.Matrix world, Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions options)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L146) | Draws a transform handle using stack-owned ABI buffers and restores native global style and masks before returning.
`world`: The current world matrix, copied into the native call.
`options`: The explicit viewport and interaction policy. | Copied output with no native pointer or domain object. | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.HelpBox(string text, string icon, System.Numerics.Vector4 color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.HelpBox.cs#L25) | Draws a wrapped contextual message with a semantic icon and a subdued status surface.
`text`: Literal message shown within the current content width.
`icon`: Icon-font glyph identifying the message severity.
`color`: Semantic accent for the icon, outline, and leading stripe. | — | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CollectionSectionHeader(string title)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.HelpBox.cs#L75) | Draws a square collection-section band whose background, separator, and padding are shared with hierarchy and Inspector presentation.
`title`: Literal section title. | — | `System.ArgumentNullException`: Thrown when is . | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.SectionLayout(System.Action drawContent)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.HelpBox.cs#L110) | Draws content in a scope where consecutive section headers become framed fieldsets.
`drawContent`: Callback that draws all content participating in the section layout. | — | `System.ArgumentNullException`: Thrown when is . | +| [`public Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.TransformGizmo(Inno.Core.Mathematics.Matrix world, Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions options)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L146) | Draws a transform handle using stack-owned ABI buffers and restores native global style and masks before returning.
`world`: The current world matrix, copied into the native call.
`options`: The explicit viewport and interaction policy. | Copied output with no native pointer or domain object. | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.HelpBox(string text, string icon, System.Numerics.Vector4 color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.HelpBox.cs#L25) | Draws a wrapped contextual message with a semantic icon and a subdued status surface.
`text`: Literal message shown within the current content width.
`icon`: Icon-font glyph identifying the message severity.
`color`: Semantic accent for the icon, outline, and leading stripe. | — | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CollectionSectionHeader(string title)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.HelpBox.cs#L75) | Draws a square collection-section band whose background, separator, and padding are shared with hierarchy and Inspector presentation.
`title`: Literal section title. | — | `System.ArgumentNullException`: Thrown when title is null. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.SectionLayout(System.Action drawContent)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.HelpBox.cs#L110) | Draws content in a scope where consecutive section headers become framed fieldsets.
`drawContent`: Callback that draws all content participating in the section layout. | — | `System.ArgumentNullException`: Thrown when drawContent is null. | | [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.isSectionContentVisible { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.HelpBox.cs#L135) | Gets whether content belonging to the current Inspector section should be drawn. | — | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.EnsureSection(string title = "Properties", string? description = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.HelpBox.cs#L153) | Ensures that subsequently drawn default properties belong to a framed section.
`title`: Title used only when the current section layout has not declared a section yet.
`description`: Optional hover explanation for the implicit section title. | when the current section accepts content; otherwise, when that section is collapsed. | `System.ArgumentNullException`: Thrown when is . | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.SectionHeader(string title, string? description = null, System.Action? drawLeadingControl = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.HelpBox.cs#L184) | Draws a section heading with hover-only description using the shared Inspector presentation.
`title`: Section title.
`description`: Optional hover explanation.
`drawLeadingControl`: Optional interactive control drawn before the section title. | when the section content should be drawn; otherwise, when the section is collapsed. | `System.ArgumentNullException`: Thrown when is . | -| [`public Inno.Editor.ImGui.ImGuiWidget.InlineRenameResult Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.InlineRename(string id, ref string text, ref bool requestFocus, float rowHeight, nuint capacity = 512, float width = -1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.InlineRename.cs#L44) | Draws a compact single-line rename editor inside an existing row.
`id`: The stable control identifier.
`text`: The mutable text buffer.
`requestFocus`: Whether keyboard focus and complete-value selection should be requested. The value remains until the input becomes active and its current contents are selected.
`rowHeight`: The height of the row area in which the field is centered.
`capacity`: The maximum UTF-8 buffer capacity.
`width`: The control width, or a negative value to fill the available space. | The current rename outcome. | `System.ArgumentException`: Thrown when is empty.
`System.ArgumentOutOfRangeException`: Thrown when is not finite or is not positive. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.EnsureSection(string title = "Properties", string? description = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.HelpBox.cs#L153) | Ensures that subsequently drawn default properties belong to a framed section.
`title`: Title used only when the current section layout has not declared a section yet.
`description`: Optional hover explanation for the implicit section title. | true when the current section accepts content; otherwise, false when that section is collapsed. | `System.ArgumentNullException`: Thrown when title is null. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.SectionHeader(string title, string? description = null, System.Action? drawLeadingControl = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.HelpBox.cs#L184) | Draws a section heading with hover-only description using the shared Inspector presentation.
`title`: Section title.
`description`: Optional hover explanation.
`drawLeadingControl`: Optional interactive control drawn before the section title. | true when the section content should be drawn; otherwise, false when the section is collapsed. | `System.ArgumentNullException`: Thrown when title is null. | +| [`public Inno.Editor.ImGui.ImGuiWidget.InlineRenameResult Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.InlineRename(string id, ref string text, ref bool requestFocus, float rowHeight, nuint capacity = 512, float width = -1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.InlineRename.cs#L44) | Draws a compact single-line rename editor inside an existing row.
`id`: The stable control identifier.
`text`: The mutable text buffer.
`requestFocus`: Whether keyboard focus and complete-value selection should be requested. The value remains true until the input becomes active and its current contents are selected.
`rowHeight`: The height of the row area in which the field is centered.
`capacity`: The maximum UTF-8 buffer capacity.
`width`: The control width, or a negative value to fill the available space. | The current rename outcome. | `System.ArgumentException`: Thrown when id is empty.
`System.ArgumentOutOfRangeException`: Thrown when rowHeight is not finite or is not positive. | | [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.isMixedValue { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.MixedValue.cs#L16) | Gets whether the currently drawn control group represents differing selected values. | — | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.MixedValue(bool mixed, System.Action draw)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.MixedValue.cs#L27) | Draws one control group with the native mixed-value state, restoring the previous item flags on failure.
`mixed`: Whether the current selection contains different values.
`draw`: Synchronous control drawing; never retained. | — | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.PanelWindow(string title, ref bool isOpen, System.Action drawBody, Inno.Editor.ImGui.ImGuiWindowFlags flags = Inno.Editor.ImGui.ImGuiWindowFlags.NoCollapse, bool useWindowPadding = true)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Panel.cs#L32) | Opens a standard panel window and executes panel body.
`title`: Window title.
`isOpen`: Visible state.
`drawBody`: Panel body callback.
`flags`: Window flags.
`useWindowPadding`: Whether the panel body should use the current standard window padding. | — | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.ConstrainedContent(string id, System.Action drawContent, bool useWindowPadding = true)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Panel.cs#L112) | Draws a vertically auto-sized content region that is constrained to the current available width and cannot create an independent scroll range.
`id`: Stable identifier used by ImGui to track the content region.
`drawContent`: Callback that draws the complete region contents.
`useWindowPadding`: Whether the region should apply the centralized standard window padding exactly once. | — | `System.ArgumentException`: Thrown when is empty.
`System.ArgumentNullException`: Thrown when is . | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.HeaderSurface(string id, System.Action drawContent, bool spanWindowPadding = false)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Panel.cs#L159) | Draws a square-cornered editor header surface using the shared target-header palette, border, and padding.
`id`: Stable identifier used by ImGui to track the header region.
`drawContent`: Callback that draws the complete header content.
`spanWindowPadding`: Whether the header should extend through the current parent window padding to both edges. | — | `System.ArgumentException`: Thrown when is empty.
`System.ArgumentNullException`: Thrown when is . | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.Hint(string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Panel.cs#L331) | Draws disabled hint text that wraps to the current content width.
`text`: Hint text. | — | `System.ArgumentNullException`: Thrown when is . | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.PropertyRow(string id, string label, System.Action drawValue, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L35) | Draws a two-column property row with a stable internal identifier.
`id`: Stable row identifier.
`label`: Human-readable property label.
`drawValue`: Value control callback.
`tooltip`: Optional hover help displayed from the property label. | — | `System.ArgumentException`: Thrown when is empty or whitespace.
`System.ArgumentNullException`: Thrown when or is . | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.PropertyRow(string id, System.Action drawLabel, System.Action drawValue)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L64) | Draws a two-column property row whose label is supplied by a custom presentation callback.
`id`: Stable row identifier.
`drawLabel`: Label presentation callback. It may wrap or draw badges inside the label column.
`drawValue`: Value control callback. | — | `System.ArgumentException`: Thrown when is empty or whitespace.
`System.ArgumentNullException`: Thrown when or is . | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.MixedValue(bool mixed, System.Action draw)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.MixedValue.cs#L27) | Draws one control group with the native mixed-value state, restoring the previous item flags on failure.
`mixed`: Whether the current selection contains different values.
`draw`: Synchronous control drawing; never retained. | — | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.PanelWindow(string title, ref bool isOpen, System.Action drawBody, Inno.Editor.ImGui.ImGuiWindowFlags flags = Inno.Editor.ImGui.ImGuiWindowFlags.NoCollapse, bool useWindowPadding = true)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Panel.cs#L32) | Opens a standard panel window and executes panel body.
`title`: Window title.
`isOpen`: Visible state.
`drawBody`: Panel body callback.
`flags`: Window flags.
`useWindowPadding`: Whether the panel body should use the current standard window padding. | — | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.ConstrainedContent(string id, System.Action drawContent, bool useWindowPadding = true)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Panel.cs#L112) | Draws a vertically auto-sized content region that is constrained to the current available width and cannot create an independent scroll range.
`id`: Stable identifier used by ImGui to track the content region.
`drawContent`: Callback that draws the complete region contents.
`useWindowPadding`: Whether the region should apply the centralized standard window padding exactly once. | — | `System.ArgumentException`: Thrown when id is empty.
`System.ArgumentNullException`: Thrown when drawContent is null. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.HeaderSurface(string id, System.Action drawContent, bool spanWindowPadding = false)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Panel.cs#L159) | Draws a square-cornered editor header surface using the shared target-header palette, border, and padding.
`id`: Stable identifier used by ImGui to track the header region.
`drawContent`: Callback that draws the complete header content.
`spanWindowPadding`: Whether the header should extend through the current parent window padding to both edges. | — | `System.ArgumentException`: Thrown when id is empty.
`System.ArgumentNullException`: Thrown when drawContent is null. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.Hint(string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Panel.cs#L331) | Draws disabled hint text that wraps to the current content width.
`text`: Hint text. | — | `System.ArgumentNullException`: Thrown when text is null. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.PropertyRow(string id, string label, System.Action drawValue, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L35) | Draws a two-column property row with a stable internal identifier.
`id`: Stable row identifier.
`label`: Human-readable property label.
`drawValue`: Value control callback.
`tooltip`: Optional hover help displayed from the property label. | — | `System.ArgumentException`: Thrown when id is empty or whitespace.
`System.ArgumentNullException`: Thrown when label or drawValue is null. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.PropertyRow(string id, System.Action drawLabel, System.Action drawValue)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L64) | Draws a two-column property row whose label is supplied by a custom presentation callback.
`id`: Stable row identifier.
`drawLabel`: Label presentation callback. It may wrap or draw badges inside the label column.
`drawValue`: Value control callback. | — | `System.ArgumentException`: Thrown when id is empty or whitespace.
`System.ArgumentNullException`: Thrown when drawLabel or drawValue is null. | | [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.SetupPropertyColumns()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L100) | Configures the label and input columns of an active table with a shared two-to-three ratio. A following fixed-width action column may be added by the caller. | — | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.PropertyLabel(string label, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L119) | Draws a label within its current table cell, wrapping when the column is narrow.
`label`: Visible label text.
`tooltip`: Optional explanation shown while the label is hovered. | — | `System.ArgumentNullException`: Thrown when is null. | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.MetadataValue(string metadata, System.Action drawValue, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L146) | Draws a subdued metadata prefix followed by an interactive value on the same line.
`metadata`: Short contextual text such as a declared value type.
`drawValue`: Callback that draws the value or action following the metadata.
`tooltip`: Optional explanation displayed while the metadata is hovered. | — | `System.ArgumentNullException`: Thrown when or is . | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.MetadataValue(string metadata, string value, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L180) | Draws one wrapped, subdued value whose metadata and content remain in the value column.
`metadata`: Short contextual text such as a declared value type.
`value`: Literal value description shown after the metadata separator.
`tooltip`: Optional explanation displayed while the combined value is hovered. | — | `System.ArgumentNullException`: Thrown when or is . | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.AxisDragFloat(string id, string axis, ref float value, float width, float speed = 0.1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L221) | Draws a float drag field with a compact colored axis prefix.
`id`: Stable control identifier.
`axis`: Axis label such as X, Y, Z, or W.
`value`: Mutable numeric value.
`width`: Total width including the axis prefix.
`speed`: Drag speed. | when the value changed. | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CompactDragFloat(string label, ref float value, float speed = 0.1, float? minimum = null, float? maximum = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L254) | Draws a floating-point drag field with a compact one-decimal presentation and precise text editing.
`label`: Stable ImGui label and identifier.
`value`: Exact floating-point value to edit. Compact presentation never rounds the stored value.
`speed`: Drag speed.
`minimum`: Optional inclusive lower bound.
`maximum`: Optional inclusive upper bound. | when the exact value changed. | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CompactSliderFloat(string label, ref float value, float minimum, float maximum)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L288) | Draws a bounded slider with compact presentation and a double-click precise input mode.
`label`: Stable ImGui label and identifier.
`value`: Exact floating-point value to edit. Compact presentation never rounds the stored value.
`minimum`: Inclusive lower bound.
`maximum`: Inclusive upper bound. | when the exact value changed. | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.AxisDragInt(string id, string axis, ref int value, float width, float speed = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L328) | Draws an integer drag field with a compact colored axis prefix.
`id`: Stable control identifier.
`axis`: Axis label such as X, Y, Z, or W.
`value`: Mutable numeric value.
`width`: Total width including the axis prefix.
`speed`: Drag speed. | when the value changed. | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.Disabled(bool disabled, System.Action draw)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L349) | Draws content inside an ImGui disabled scope when requested.
`disabled`: Whether interaction is disabled.
`draw`: Drawing callback. | — | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.InsertionLine(float fromX, float toX, float y)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L378) | Draws a horizontal insertion marker above normal window content in screen coordinates.
`fromX`: Marker start X coordinate.
`toX`: Marker end X coordinate.
`y`: Marker Y coordinate. | — | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DropTargetHighlight(System.Numerics.Vector2 min, System.Numerics.Vector2 max)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L398) | Draws the standard yellow rectangular drag-and-drop target highlight above all normal window content in screen coordinates.
`min`: Minimum target coordinate.
`max`: Maximum target coordinate. | — | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.SearchInput(string id, string hint, ref string query, nuint capacity = 256, float width = -1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Search.cs#L35) | Draws a single-line search field with a stable identifier.
`id`: The stable control identifier.
`hint`: The hint shown while the query is empty.
`query`: The mutable search query.
`capacity`: The maximum UTF-8 buffer capacity.
`width`: The control width, or a negative value to fill the available space. | when the query changed; otherwise, . | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginSearchPopup(string id, ref string query, string hint, nuint capacity = 256, float width = -1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Search.cs#L69) | Begins a popup and draws its focused search field.
`id`: The popup identifier previously supplied to ImGui.
`query`: The mutable search query.
`hint`: The hint shown while the query is empty.
`capacity`: The maximum UTF-8 buffer capacity.
`width`: The search field width, or a negative value to use the editor default. | when popup content should be drawn; otherwise, . | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.EndSearchPopup()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Search.cs#L92) | Ends a popup opened by . | — | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.SelectTarget(Inno.Editor.Interactions.EditorInteractions interactions, Inno.Core.Identity.IdentityObject target, System.Collections.Generic.IReadOnlyList visibleTargets)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L28) | Applies ordinary, additive or visible-range selection using the active keyboard modifiers.
`interactions`: The session's authoritative interaction service.
`target`: The freshly resolved clicked target.
`visibleTargets`: Current runtime-identity view order; collapsed or filtered items must be omitted. | — | — | -| [`public Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.NavigateList(Inno.Editor.Interactions.EditorInteractions interactions, int itemCount, int focusedIndex, int pageSize = 10)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L74) | Reads one focused list's keyboard navigation without retaining its entries or changing domain selection.
`interactions`: The authoritative interaction owner supplying the product modifier policy.
`itemCount`: The number of currently visible, ordered entries.
`focusedIndex`: The current visible focus index, or minus one when absent.
`pageSize`: The positive number of visible rows advanced by Page Up or Page Down. | Neutral focus and selection intents; text editing, active controls and popups produce no intent. | `System.ArgumentNullException`: The interaction owner is null.
`System.ArgumentOutOfRangeException`: The count, focus index or page size is invalid.
`System.InvalidOperationException`: No matching owner-thread drawing session is active. | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginBoundedCombo(string id, string preview, Inno.Editor.ImGui.ImGuiComboFlags flags = Inno.Editor.ImGui.ImGuiComboFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selector.cs#L37) | Begins a combo whose popup opens below the control and stays within its containing window.
`id`: Stable combo identifier in the current ImGui scope.
`preview`: Text displayed by the closed combo.
`flags`: Native combo presentation flags. Only is supported. | when the combo popup is open and its contents should be submitted; otherwise, . | `System.ArgumentException`: Thrown when is empty.
`System.ArgumentNullException`: Thrown when is null.
`System.ArgumentOutOfRangeException`: Thrown when contains a presentation mode unsupported by the editor selector. | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.EndBoundedCombo()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selector.cs#L55) | Ends a combo opened by . | — | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginMenuSelector(string id, string preview, float width, float minimumPopupWidth)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selector.cs#L84) | Draws a compact selector control and begins a work-area-bounded menu popup.
`id`: Stable selector identifier in the current ImGui scope.
`preview`: Text displayed by the closed selector.
`width`: Width reserved for the selector control.
`minimumPopupWidth`: Minimum outer width of the popup, including its window padding. | when the popup is open and its contents should be submitted; otherwise, . | `System.ArgumentException`: Thrown when is empty.
`System.ArgumentNullException`: Thrown when is .
`System.ArgumentOutOfRangeException`: Thrown when or is not positive. | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.EndMenuSelector()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selector.cs#L122) | Ends a selector popup opened by . | — | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.PropertyLabel(string label, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L119) | Draws a label within its current table cell, wrapping when the column is narrow.
`label`: Visible label text.
`tooltip`: Optional explanation shown while the label is hovered. | — | `System.ArgumentNullException`: Thrown when label is null. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.MetadataValue(string metadata, System.Action drawValue, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L146) | Draws a subdued metadata prefix followed by an interactive value on the same line.
`metadata`: Short contextual text such as a declared value type.
`drawValue`: Callback that draws the value or action following the metadata.
`tooltip`: Optional explanation displayed while the metadata is hovered. | — | `System.ArgumentNullException`: Thrown when metadata or drawValue is null. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.MetadataValue(string metadata, string value, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L180) | Draws one wrapped, subdued value whose metadata and content remain in the value column.
`metadata`: Short contextual text such as a declared value type.
`value`: Literal value description shown after the metadata separator.
`tooltip`: Optional explanation displayed while the combined value is hovered. | — | `System.ArgumentNullException`: Thrown when metadata or value is null. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.AxisDragFloat(string id, string axis, ref float value, float width, float speed = 0.1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L221) | Draws a float drag field with a compact colored axis prefix.
`id`: Stable control identifier.
`axis`: Axis label such as X, Y, Z, or W.
`value`: Mutable numeric value.
`width`: Total width including the axis prefix.
`speed`: Drag speed. | true when the value changed. | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CompactDragFloat(string label, ref float value, float speed = 0.1, float? minimum = null, float? maximum = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L254) | Draws a floating-point drag field with a compact one-decimal presentation and precise text editing.
`label`: Stable ImGui label and identifier.
`value`: Exact floating-point value to edit. Compact presentation never rounds the stored value.
`speed`: Drag speed.
`minimum`: Optional inclusive lower bound.
`maximum`: Optional inclusive upper bound. | true when the exact value changed. | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CompactSliderFloat(string label, ref float value, float minimum, float maximum)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L288) | Draws a bounded slider with compact presentation and a double-click precise input mode.
`label`: Stable ImGui label and identifier.
`value`: Exact floating-point value to edit. Compact presentation never rounds the stored value.
`minimum`: Inclusive lower bound.
`maximum`: Inclusive upper bound. | true when the exact value changed. | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.AxisDragInt(string id, string axis, ref int value, float width, float speed = 1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L328) | Draws an integer drag field with a compact colored axis prefix.
`id`: Stable control identifier.
`axis`: Axis label such as X, Y, Z, or W.
`value`: Mutable numeric value.
`width`: Total width including the axis prefix.
`speed`: Drag speed. | true when the value changed. | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.Disabled(bool disabled, System.Action draw)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L349) | Draws content inside an ImGui disabled scope when requested.
`disabled`: Whether interaction is disabled.
`draw`: Drawing callback. | — | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.InsertionLine(float fromX, float toX, float y)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L378) | Draws a horizontal insertion marker above normal window content in screen coordinates.
`fromX`: Marker start X coordinate.
`toX`: Marker end X coordinate.
`y`: Marker Y coordinate. | — | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.DropTargetHighlight(System.Numerics.Vector2 min, System.Numerics.Vector2 max)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Property.cs#L398) | Draws the standard yellow rectangular drag-and-drop target highlight above all normal window content in screen coordinates.
`min`: Minimum target coordinate.
`max`: Maximum target coordinate. | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.SearchInput(string id, string hint, ref string query, nuint capacity = 256, float width = -1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Search.cs#L35) | Draws a single-line search field with a stable identifier.
`id`: The stable control identifier.
`hint`: The hint shown while the query is empty.
`query`: The mutable search query.
`capacity`: The maximum UTF-8 buffer capacity.
`width`: The control width, or a negative value to fill the available space. | true when the query changed; otherwise, false. | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginSearchPopup(string id, ref string query, string hint, nuint capacity = 256, float width = -1)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Search.cs#L69) | Begins a popup and draws its focused search field.
`id`: The popup identifier previously supplied to ImGui.
`query`: The mutable search query.
`hint`: The hint shown while the query is empty.
`capacity`: The maximum UTF-8 buffer capacity.
`width`: The search field width, or a negative value to use the editor default. | true when popup content should be drawn; otherwise, false. | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.EndSearchPopup()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Search.cs#L92) | Ends a popup opened by Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginSearchPopup(System.String,System.String@,System.String,System.UIntPtr,System.Single). | — | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.SelectTarget(Inno.Editor.Interactions.EditorInteractions interactions, Inno.Core.Identity.IdentityObject target, System.Collections.Generic.IReadOnlyList visibleTargets)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L28) | Applies ordinary, additive or visible-range selection using the active keyboard modifiers.
`interactions`: The session's authoritative interaction service.
`target`: The freshly resolved clicked target.
`visibleTargets`: Current runtime-identity view order; collapsed or filtered items must be omitted. | — | — | +| [`public Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.NavigateList(Inno.Editor.Interactions.EditorInteractions interactions, int itemCount, int focusedIndex, int pageSize = 10)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L74) | Reads one focused list's keyboard navigation without retaining its entries or changing domain selection.
`interactions`: The authoritative interaction owner supplying the product modifier policy.
`itemCount`: The number of currently visible, ordered entries.
`focusedIndex`: The current visible focus index, or minus one when absent.
`pageSize`: The positive number of visible rows advanced by Page Up or Page Down. | Neutral focus and selection intents; text editing, active controls and popups produce no intent. | `System.ArgumentNullException`: The interaction owner is null.
`System.ArgumentOutOfRangeException`: The count, focus index or page size is invalid.
`System.InvalidOperationException`: No matching owner-thread drawing session is active. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginBoundedCombo(string id, string preview, Inno.Editor.ImGui.ImGuiComboFlags flags = Inno.Editor.ImGui.ImGuiComboFlags.None)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selector.cs#L37) | Begins a combo whose popup opens below the control and stays within its containing window.
`id`: Stable combo identifier in the current ImGui scope.
`preview`: Text displayed by the closed combo.
`flags`: Native combo presentation flags. Only F:Inno.Editor.ImGui.ImGuiComboFlags.WidthFitPreview is supported. | true when the combo popup is open and its contents should be submitted; otherwise, false. | `System.ArgumentException`: Thrown when id is empty.
`System.ArgumentNullException`: Thrown when preview is null.
`System.ArgumentOutOfRangeException`: Thrown when flags contains a presentation mode unsupported by the editor selector. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.EndBoundedCombo()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selector.cs#L55) | Ends a combo opened by Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginBoundedCombo(System.String,System.String,Inno.Editor.ImGui.ImGuiComboFlags). | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginMenuSelector(string id, string preview, float width, float minimumPopupWidth)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selector.cs#L84) | Draws a compact selector control and begins a work-area-bounded menu popup.
`id`: Stable selector identifier in the current ImGui scope.
`preview`: Text displayed by the closed selector.
`width`: Width reserved for the selector control.
`minimumPopupWidth`: Minimum outer width of the popup, including its window padding. | true when the popup is open and its contents should be submitted; otherwise, false. | `System.ArgumentException`: Thrown when id is empty.
`System.ArgumentNullException`: Thrown when preview is null.
`System.ArgumentOutOfRangeException`: Thrown when width or minimumPopupWidth is not positive. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.EndMenuSelector()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selector.cs#L122) | Ends a selector popup opened by Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.BeginMenuSelector(System.String,System.String,System.Single,System.Single). | — | — | | [`public Inno.Editor.ImGui.EditorStyleMetrics Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.style { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Style.cs#L17) | Gets the centralized editor layout metrics shared by every widget and feature panel. | — | — | | [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.SetupStyle()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Style.cs#L22) | Applies the centralized editor layout metrics and palette to the current ImGui context. | — | — | | [`public float Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.GetIconCatalogWidth()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L21) | Measures the standard glyph column once per native frame in this UI session. | The widest visible standard glyph at the current font size, at least one text-line height. | — | -| [`public System.Numerics.Vector4 Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.GetGlyphVisualBounds(float fontSize, string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L55) | Measures a glyph using the current font without exposing its native font handle.
`fontSize`: The positive baked font size.
`text`: A nonempty string whose first Unicode scalar identifies the glyph. | The glyph's visible left, top, right and bottom offsets. | `System.ArgumentException`: The glyph text is empty. | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.AddGlyphCentered(float fontSize, string text, System.Numerics.Vector2 center, uint color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L78) | Centers a glyph in the current window without exposing a native draw list.
`fontSize`: The positive baked font size.
`text`: The glyph text.
`center`: The requested visible center in screen coordinates.
`color`: Packed text color. | — | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.ClickableText(string id, string text, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L182) | Draws clickable text without a persistent or hovered background.
`id`: Stable identifier used by ImGui to track the interaction.
`text`: Visible text or icon glyph.
`tooltip`: Optional tooltip displayed while the interaction is hovered. | when the text is pressed. | `System.ArgumentException`: Thrown when is empty.
`System.ArgumentNullException`: Thrown when is . | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.HoverText(string id, string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L205) | Draws a text link with no button background and highlights it only through text presentation.
`id`: Stable identifier used by ImGui to track the interaction.
`text`: Visible link text. | when the link is pressed. | `System.ArgumentException`: Thrown when is empty.
`System.ArgumentNullException`: Thrown when is . | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.ClickableIcon(string id, string icon, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L252) | Draws a clickable icon inside the same square interaction slot used by editor close controls. The icon has no resting background and changes only its glyph color while hovered or active.
`id`: Stable identifier used by ImGui to track the interaction.
`icon`: The visible icon glyph.
`tooltip`: Optional tooltip displayed while the interaction is hovered. | when the icon is pressed. | `System.ArgumentException`: Thrown when is empty.
`System.ArgumentNullException`: Thrown when is . | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.ClickableText(string id, string text, System.Numerics.Vector2 controlSize, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L303) | Draws clickable text centered inside an explicitly sized transparent interaction area.
`id`: Stable identifier used by ImGui to track the interaction.
`text`: Visible text or icon glyph.
`controlSize`: Size of the transparent interaction area.
`tooltip`: Optional tooltip displayed while the interaction is hovered. | when the text is pressed. | `System.ArgumentException`: Thrown when is empty.
`System.ArgumentNullException`: Thrown when is .
`System.ArgumentOutOfRangeException`: Thrown when either component of is not positive. | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CenteredText(string text, System.Numerics.Vector2 areaSize)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L347) | Draws non-interactive text centered inside a reserved layout area.
`text`: Visible text.
`areaSize`: Size of the layout area that contains the text. | — | `System.ArgumentNullException`: Thrown when is .
`System.ArgumentOutOfRangeException`: Thrown when either component of is not positive. | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CenteredWrappedText(string text, System.Numerics.Vector2 areaSize, System.Numerics.Vector2 padding)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L382) | Draws wrapped non-interactive text as a centered block inside a padded layout area.
`text`: The literal text to wrap and draw.
`areaSize`: The complete area reserved by the widget.
`padding`: The minimum horizontal and vertical distance retained from the area edges whenever space permits. | — | `System.ArgumentNullException`: Thrown when is .
`System.ArgumentOutOfRangeException`: Thrown when an area component is not positive or a padding component is negative. | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.ColoredText(System.Numerics.Vector4 color, string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L433) | Draws unformatted text with a temporary foreground color.
`color`: The foreground color applied only while drawing the text.
`text`: The literal text to draw without format-string interpretation. | — | `System.ArgumentNullException`: Thrown when is . | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.WrappedText(string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L460) | Draws literal text wrapped to the remaining content width without using a native variadic formatting entry point.
`text`: The literal text to draw. | — | `System.ArgumentNullException`: Thrown when is . | -| [`public System.Numerics.Vector2 Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.GetClickableTextSize(string text, System.Numerics.Vector2 padding)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L493) | Calculates a clickable text area from visible text and requested inner padding.
`text`: Visible text whose dimensions determine the content size.
`padding`: Horizontal and vertical padding surrounding the text. | The complete transparent interaction area size. | `System.ArgumentNullException`: Thrown when is .
`System.ArgumentOutOfRangeException`: Thrown when either component of is negative. | -| [`public System.Numerics.Vector2 Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.GetCompactClickableTextSize()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L514) | Gets the compact fixed interaction size used by icon-style clickable text. | A fixed-size area that follows the editor icon slot convention. | — | -| [`public System.Numerics.Vector2 Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.GetCompactIconSize()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L527) | Gets the square icon interaction size shared by dock-header close controls and compact editor icons. | A square size based on the current ImGui font size. | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.IconText(string icon, string text, bool highlight)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L560) | Draws icon and text with the icon's visible glyph bounds centered in a slot that expands when the glyph is wider than the normal editor icon slot.
`icon`: Icon text.
`text`: Main text.
`highlight`: Whether to underline and emphasize the drawn icon and text. | — | — | -| [`public Inno.Editor.ImGui.ImGuiWidget.TreeNodeResult Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.TreeNode(string id, System.Action onDraw, in Inno.Editor.ImGui.ImGuiWidget.TreeNodeOptions options)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L42) | Draws a full-width interactive tree row whose non-leaf content toggles expansion when double-clicked, while preserving single-click disclosure-arrow behavior.
`id`: Stable row identifier.
`onDraw`: Frame-local content drawing for visible or explicitly preserved rows; clipped ordinary rows do not invoke it.
`options`: Tree row options. | Interaction and row geometry for the submitted item. | `System.ArgumentOutOfRangeException`: An explicit flattened depth is negative. | +| [`public System.Numerics.Vector4 Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.GetGlyphVisualBounds(float fontSize, string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L55) | Measures a glyph using the current font without exposing its native font handle.
`fontSize`: The positive baked font size.
`text`: A nonempty string whose first Unicode scalar identifies the glyph. | The glyph's visible left, top, right and bottom offsets. | `System.ArgumentException`: The glyph text is empty. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.AddGlyphCentered(float fontSize, string text, System.Numerics.Vector2 center, uint color)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L78) | Centers a glyph in the current window without exposing a native draw list.
`fontSize`: The positive baked font size.
`text`: The glyph text.
`center`: The requested visible center in screen coordinates.
`color`: Packed text color. | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.ClickableText(string id, string text, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L182) | Draws clickable text without a persistent or hovered background.
`id`: Stable identifier used by ImGui to track the interaction.
`text`: Visible text or icon glyph.
`tooltip`: Optional tooltip displayed while the interaction is hovered. | true when the text is pressed. | `System.ArgumentException`: Thrown when id is empty.
`System.ArgumentNullException`: Thrown when text is null. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.HoverText(string id, string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L205) | Draws a text link with no button background and highlights it only through text presentation.
`id`: Stable identifier used by ImGui to track the interaction.
`text`: Visible link text. | true when the link is pressed. | `System.ArgumentException`: Thrown when id is empty.
`System.ArgumentNullException`: Thrown when text is null. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.ClickableIcon(string id, string icon, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L252) | Draws a clickable icon inside the same square interaction slot used by editor close controls. The icon has no resting background and changes only its glyph color while hovered or active.
`id`: Stable identifier used by ImGui to track the interaction.
`icon`: The visible icon glyph.
`tooltip`: Optional tooltip displayed while the interaction is hovered. | true when the icon is pressed. | `System.ArgumentException`: Thrown when id is empty.
`System.ArgumentNullException`: Thrown when icon is null. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.ClickableText(string id, string text, System.Numerics.Vector2 controlSize, string? tooltip = null)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L303) | Draws clickable text centered inside an explicitly sized transparent interaction area.
`id`: Stable identifier used by ImGui to track the interaction.
`text`: Visible text or icon glyph.
`controlSize`: Size of the transparent interaction area.
`tooltip`: Optional tooltip displayed while the interaction is hovered. | true when the text is pressed. | `System.ArgumentException`: Thrown when id is empty.
`System.ArgumentNullException`: Thrown when text is null.
`System.ArgumentOutOfRangeException`: Thrown when either component of controlSize is not positive. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CenteredText(string text, System.Numerics.Vector2 areaSize)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L347) | Draws non-interactive text centered inside a reserved layout area.
`text`: Visible text.
`areaSize`: Size of the layout area that contains the text. | — | `System.ArgumentNullException`: Thrown when text is null.
`System.ArgumentOutOfRangeException`: Thrown when either component of areaSize is not positive. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.CenteredWrappedText(string text, System.Numerics.Vector2 areaSize, System.Numerics.Vector2 padding)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L382) | Draws wrapped non-interactive text as a centered block inside a padded layout area.
`text`: The literal text to wrap and draw.
`areaSize`: The complete area reserved by the widget.
`padding`: The minimum horizontal and vertical distance retained from the area edges whenever space permits. | — | `System.ArgumentNullException`: Thrown when text is null.
`System.ArgumentOutOfRangeException`: Thrown when an area component is not positive or a padding component is negative. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.ColoredText(System.Numerics.Vector4 color, string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L433) | Draws unformatted text with a temporary foreground color.
`color`: The foreground color applied only while drawing the text.
`text`: The literal text to draw without format-string interpretation. | — | `System.ArgumentNullException`: Thrown when text is null. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.WrappedText(string text)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L466) | Draws literal text wrapped to the remaining content width without using a native variadic formatting entry point.
`text`: The literal text to draw. | — | `System.ArgumentNullException`: Thrown when text is null.
`System.InvalidOperationException`: The owning UI thread, frame or native context is not active.
`System.ObjectDisposedException`: The owning UI session has retired. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.WrappedText(string text, float wrapWidth)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L494) | Draws literal text at an explicitly measured wrap width, independent of a scrolling window's virtual content extent.
`text`: The literal text captured for the current layout.
`wrapWidth`: The measured positive width in current presentation coordinates. | — | `System.ArgumentNullException`: The text is null.
`System.ArgumentOutOfRangeException`: The width is not finite and positive.
`System.InvalidOperationException`: The owning UI thread, frame or native context is not active.
`System.ObjectDisposedException`: The owning UI session has retired. | +| [`public System.Numerics.Vector2 Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.GetClickableTextSize(string text, System.Numerics.Vector2 padding)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L532) | Calculates a clickable text area from visible text and requested inner padding.
`text`: Visible text whose dimensions determine the content size.
`padding`: Horizontal and vertical padding surrounding the text. | The complete transparent interaction area size. | `System.ArgumentNullException`: Thrown when text is null.
`System.ArgumentOutOfRangeException`: Thrown when either component of padding is negative. | +| [`public System.Numerics.Vector2 Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.GetCompactClickableTextSize()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L553) | Gets the compact fixed interaction size used by icon-style clickable text. | A fixed-size area that follows the editor icon slot convention. | — | +| [`public System.Numerics.Vector2 Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.GetCompactIconSize()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L566) | Gets the square icon interaction size shared by dock-header close controls and compact editor icons. | A square size based on the current ImGui font size. | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.IconText(string icon, string text, bool highlight)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs#L599) | Draws icon and text with the icon's visible glyph bounds centered in a slot that expands when the glyph is wider than the normal editor icon slot.
`icon`: Icon text.
`text`: Main text.
`highlight`: Whether to underline and emphasize the drawn icon and text. | — | — | +| [`public Inno.Editor.ImGui.ImGuiWidget.TreeNodeResult Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.TreeNode(string id, System.Action onDraw, in Inno.Editor.ImGui.ImGuiWidget.TreeNodeOptions options)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L42) | Draws a full-width interactive tree row whose non-leaf content toggles expansion when double-clicked, while preserving single-click disclosure-arrow behavior.
`id`: Stable row identifier.
`onDraw`: Frame-local content drawing for visible or explicitly preserved rows; clipped ordinary rows do not invoke it.
`options`: Tree row options. | Interaction and row geometry for the submitted item. | `System.ArgumentOutOfRangeException`: An explicit flattened depth is negative. | | [`public ulong Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.treeExpansionRevision { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L70) | Gets this window and owner's expansion change counter for invalidating neutral flattened views. | — | `System.InvalidOperationException`: No valid drawing session or native frame is active. | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.IsTreeNodeOpen(string id)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L94) | Reads a retained expansion value without submitting a native row or retaining domain objects.
`id`: The stable row identifier within this window and owner. | True when the row was explicitly expanded; unknown rows are collapsed. | `System.ArgumentException`: The row identifier is empty or whitespace.
`System.InvalidOperationException`: No valid drawing session or native frame is active. | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.SetTreeNodeOpen(string id, bool open)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L116) | Changes retained expansion before a flattened view is computed, without submitting a row.
`id`: The stable row identifier within this window and owner.
`open`: The requested disclosure state. | — | `System.ArgumentException`: The row identifier is empty or whitespace.
`System.InvalidOperationException`: No valid drawing session or native frame is active. | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.SetNextTreeNodeOpen(bool open)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L261) | Overrides the retained expansion state of the next submitted non-leaf tree row.
`open`: Whether the next row should be expanded. | — | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.Trend(string label, System.ReadOnlySpan values, int offset = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Trend.cs#L34) | Draws a bounded line plot from borrowed numeric samples without copying their buffer.
`label`: The visible plot title and stable item identifier in its current owner.
`values`: Finite samples borrowed only for this call; an empty span draws an empty plot.
`offset`: The first chronological sample in a circular buffer, or zero for empty input. | — | `System.ArgumentException`: The label is empty or a sample is not finite.
`System.ArgumentOutOfRangeException`: The offset is outside the supplied sample span.
`System.InvalidOperationException`: No matching owner-thread drawing session is active. | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.IsTreeNodeOpen(string id)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L94) | Reads a retained expansion value without submitting a native row or retaining domain objects.
`id`: The stable row identifier within this window and owner. | True when the row was explicitly expanded; unknown rows are collapsed. | `System.ArgumentException`: The row identifier is empty or whitespace.
`System.InvalidOperationException`: No valid drawing session or native frame is active. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.SetTreeNodeOpen(string id, bool open)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L116) | Changes retained expansion before a flattened view is computed, without submitting a row.
`id`: The stable row identifier within this window and owner.
`open`: The requested disclosure state. | — | `System.ArgumentException`: The row identifier is empty or whitespace.
`System.InvalidOperationException`: No valid drawing session or native frame is active. | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.SetNextTreeNodeOpen(bool open)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L261) | Overrides the retained expansion state of the next submitted non-leaf tree row.
`open`: Whether the next row should be expanded. | — | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.ImGuiWidget.Trend(string label, System.ReadOnlySpan values, int offset = 0)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Trend.cs#L34) | Draws a bounded line plot from borrowed numeric samples without copying their buffer.
`label`: The visible plot title and stable item identifier in its current owner.
`values`: Finite samples borrowed only for this call; an empty span draws an empty plot.
`offset`: The first chronological sample in a circular buffer, or zero for empty input. | — | `System.ArgumentException`: The label is empty or a sample is not finite.
`System.ArgumentOutOfRangeException`: The offset is outside the supplied sample span.
`System.InvalidOperationException`: No matching owner-thread drawing session is active. | +| [`public readonly record struct Inno.Editor.ImGui.ImGuiWidget.DialogPresentation : System.IEquatable`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L33) | Describes immutable content for a measured message dialog. Actions are returned to its owner, never retained as callbacks.
`message`: The current status or error text.
`progress`: A completed fraction, or null when no progress bar is needed.
`indeterminate`: Whether to show activity without inventing a completed fraction.
`actionLabel`: The optional centered action label.
`actionEnabled`: Whether the current operation admits the action.
`details`: Optional expanded diagnostic text sharing the message scroll owner.
`cancelOnEscape`: Whether Escape activates this action; opt in only for cancellation or dismissal. | — | — | +| [`public Inno.Editor.ImGui.ImGuiWidget.DialogPresentation.DialogPresentation(string message, float? progress = null, bool indeterminate = false, string? actionLabel = null, bool actionEnabled = true, string? details = null, bool cancelOnEscape = false)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L33) | Describes immutable content for a measured message dialog. Actions are returned to its owner, never retained as callbacks.
`message`: The current status or error text.
`progress`: A completed fraction, or null when no progress bar is needed.
`indeterminate`: Whether to show activity without inventing a completed fraction.
`actionLabel`: The optional centered action label.
`actionEnabled`: Whether the current operation admits the action.
`details`: Optional expanded diagnostic text sharing the message scroll owner.
`cancelOnEscape`: Whether Escape activates this action; opt in only for cancellation or dismissal. | — | — | +| [`public string Inno.Editor.ImGui.ImGuiWidget.DialogPresentation.message { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L34) | The current status or error text. | — | — | +| [`public float? Inno.Editor.ImGui.ImGuiWidget.DialogPresentation.progress { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L35) | A completed fraction, or null when no progress bar is needed. | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.DialogPresentation.indeterminate { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L36) | Whether to show activity without inventing a completed fraction. | — | — | +| [`public string? Inno.Editor.ImGui.ImGuiWidget.DialogPresentation.actionLabel { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L37) | The optional centered action label. | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.DialogPresentation.actionEnabled { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L38) | Whether the current operation admits the action. | — | — | +| [`public string? Inno.Editor.ImGui.ImGuiWidget.DialogPresentation.details { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L39) | Optional expanded diagnostic text sharing the message scroll owner. | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.DialogPresentation.cancelOnEscape { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L40) | Whether Escape activates this action; opt in only for cancellation or dismissal. | — | — | +| [`public override string Inno.Editor.ImGui.ImGuiWidget.DialogPresentation.ToString()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L33) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | +| [`public static bool Inno.Editor.ImGui.ImGuiWidget.DialogPresentation.operator !=(Inno.Editor.ImGui.ImGuiWidget.DialogPresentation left, Inno.Editor.ImGui.ImGuiWidget.DialogPresentation right)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L33) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.ImGui.ImGuiWidget.DialogPresentation.operator ==(Inno.Editor.ImGui.ImGuiWidget.DialogPresentation left, Inno.Editor.ImGui.ImGuiWidget.DialogPresentation right)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L33) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public override int Inno.Editor.ImGui.ImGuiWidget.DialogPresentation.GetHashCode()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L33) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | +| [`public override bool Inno.Editor.ImGui.ImGuiWidget.DialogPresentation.Equals(object obj)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L33) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.DialogPresentation.Equals(Inno.Editor.ImGui.ImGuiWidget.DialogPresentation other)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L33) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.DialogPresentation.Deconstruct(out string message, out float? progress, out bool indeterminate, out string? actionLabel, out bool actionEnabled, out string? details, out bool cancelOnEscape)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L33) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public readonly struct Inno.Editor.ImGui.ImGuiWidget.DialogLayout`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L46) | Carries a measured dialog layout. Only its required extent is public; drawing mechanics remain owned by the widget. | — | — | +| [`public System.Numerics.Vector2 Inno.Editor.ImGui.ImGuiWidget.DialogLayout.size { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs#L67) | Gets the content extent, excluding the window title, border and padding. | — | — | | [`public enum Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOperation : int`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L14) | Chooses the transform handles rendered by the viewport presenter. | — | — | | [`Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOperation.Translate = 1`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L19) | Renders translation handles. | — | — | | [`Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOperation.Rotate = 2`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L23) | Renders rotation handles. | — | — | @@ -2618,26 +2697,26 @@ static void DrawHelp() | [`public bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions.maskY { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L101) | Gets whether the Y translation axis is excluded by the viewport plane. | — | — | | [`public bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions.maskZ { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L105) | Gets whether the Z translation axis is excluded by the viewport plane. | — | — | | [`public override string Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions.ToString()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L60) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | -| [`public static bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions.operator !=(Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions left, Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions right)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L60) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions.operator ==(Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions left, Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions right)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L60) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions.operator !=(Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions left, Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions right)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L60) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions.operator ==(Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions left, Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions right)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L60) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions.GetHashCode()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L60) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions.Equals(object obj)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L60) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions.Equals(Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions other)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L60) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | -| [`public readonly record struct Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult : System.IEquatable`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | Returns copied manipulation output; the domain owner decides how to apply and record it.
`matrix`: The resulting world matrix.
`changed`: Whether the native presenter reported an edited value.
`isUsing`: Whether the handle currently captures the pointer.
`isOver`: Whether the pointer is over a handle. | — | — | -| [`public Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.TransformGizmoResult(Inno.Core.Mathematics.Matrix matrix, bool changed, bool isUsing, bool isOver)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | Returns copied manipulation output; the domain owner decides how to apply and record it.
`matrix`: The resulting world matrix.
`changed`: Whether the native presenter reported an edited value.
`isUsing`: Whether the handle currently captures the pointer.
`isOver`: Whether the pointer is over a handle. | — | — | +| [`public override bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions.Equals(object obj)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L60) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions.Equals(Inno.Editor.ImGui.ImGuiWidget.TransformGizmoOptions other)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L60) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | +| [`public readonly record struct Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult : System.IEquatable`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | Returns copied manipulation output; the domain owner decides how to apply and record it.
`matrix`: The resulting world matrix.
`changed`: Whether the native presenter reported an edited value.
`isUsing`: Whether the handle currently captures the pointer.
`isOver`: Whether the pointer is over a handle. | — | — | +| [`public Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.TransformGizmoResult(Inno.Core.Mathematics.Matrix matrix, bool changed, bool isUsing, bool isOver)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | Returns copied manipulation output; the domain owner decides how to apply and record it.
`matrix`: The resulting world matrix.
`changed`: Whether the native presenter reported an edited value.
`isUsing`: Whether the handle currently captures the pointer.
`isOver`: Whether the pointer is over a handle. | — | — | | [`public Inno.Core.Mathematics.Matrix Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.matrix { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L124) | The resulting world matrix. | — | — | | [`public bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.changed { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L125) | Whether the native presenter reported an edited value. | — | — | | [`public bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.isUsing { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L126) | Whether the handle currently captures the pointer. | — | — | | [`public bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.isOver { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L127) | Whether the pointer is over a handle. | — | — | | [`public override string Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.ToString()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | -| [`public static bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.operator !=(Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult left, Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult right)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.operator ==(Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult left, Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult right)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.operator !=(Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult left, Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult right)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.operator ==(Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult left, Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult right)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.GetHashCode()`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.Equals(object obj)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.Equals(Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult other)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | -| [`public void Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.Deconstruct(out Inno.Core.Mathematics.Matrix matrix, out bool changed, out bool isUsing, out bool isOver)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | Inherited or compiler-provided contract. | — | — | +| [`public override bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.Equals(object obj)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.Equals(Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult other)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | +| [`public void Inno.Editor.ImGui.ImGuiWidget.TransformGizmoResult.Deconstruct(out Inno.Core.Mathematics.Matrix matrix, out bool changed, out bool isUsing, out bool isOver)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Gizmo.cs#L123) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public sealed class Inno.Editor.ImGui.ImGuiWidget.InlineRenamePresentation`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.InlineRename.cs#L141) | Describes the view-owned geometry used to present an active inline rename action. | — | — | -| [`public Inno.Editor.ImGui.ImGuiWidget.InlineRenamePresentation.InlineRenamePresentation(string id, float width, float rowHeight, nuint bufferSize = 512)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.InlineRename.cs#L165) | Creates inline rename presentation data.
`id`: The stable ImGui identifier used by the input field.
`width`: The requested input width in logical pixels.
`rowHeight`: The height of the row area in which the field is centered.
`bufferSize`: The maximum UTF-8 buffer size accepted by the input. | — | `System.ArgumentException`: Thrown when is empty.
`System.ArgumentOutOfRangeException`: Thrown when or is not finite and positive, or when is zero. | +| [`public Inno.Editor.ImGui.ImGuiWidget.InlineRenamePresentation.InlineRenamePresentation(string id, float width, float rowHeight, nuint bufferSize = 512)`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.InlineRename.cs#L165) | Creates inline rename presentation data.
`id`: The stable ImGui identifier used by the input field.
`width`: The requested input width in logical pixels.
`rowHeight`: The height of the row area in which the field is centered.
`bufferSize`: The maximum UTF-8 buffer size accepted by the input. | — | `System.ArgumentException`: Thrown when id is empty.
`System.ArgumentOutOfRangeException`: Thrown when width or rowHeight is not finite and positive, or when bufferSize is zero. | | [`public string Inno.Editor.ImGui.ImGuiWidget.InlineRenamePresentation.id { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.InlineRename.cs#L197) | Gets the stable ImGui identifier used by the input field. | — | — | | [`public float Inno.Editor.ImGui.ImGuiWidget.InlineRenamePresentation.width { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.InlineRename.cs#L201) | Gets the requested input width in logical pixels. | — | — | | [`public float Inno.Editor.ImGui.ImGuiWidget.InlineRenamePresentation.rowHeight { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.InlineRename.cs#L205) | Gets the height of the row area in which the input field is centered. | — | — | @@ -2647,15 +2726,15 @@ static void DrawHelp() | [`Inno.Editor.ImGui.ImGuiWidget.InlineRenameResult.Commit = 1`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.InlineRename.cs#L224) | Indicates that the edited text should be committed. | — | — | | [`Inno.Editor.ImGui.ImGuiWidget.InlineRenameResult.FocusLost = 2`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.InlineRename.cs#L228) | Indicates that the input lost focus and its valid value should be committed before closing. | — | — | | [`Inno.Editor.ImGui.ImGuiWidget.InlineRenameResult.Cancel = 3`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.InlineRename.cs#L232) | Indicates that the edited text should be discarded. | — | — | -| [`public readonly struct Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L166) | Carries frame-local list navigation intents over visible indices without owning objects or selection state. | — | — | -| [`public int Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.focusedIndex { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L191) | Gets the resulting visible focus index, or minus one for no focus. | — | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.focusChanged { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L195) | Gets whether the visible focus index changed. | — | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.selectionRequested { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L199) | Gets whether the caller should apply a domain selection operation. | — | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.extendRange { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L203) | Gets whether the selection should extend from its existing anchor. | — | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.additive { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L207) | Gets whether the product's primary modifier requests preserving other selected entries. | — | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.toggle { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L211) | Gets whether Space with the primary modifier requests toggling the focused entry. | — | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.activate { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L215) | Gets whether Enter requests activation of the focused entry. | — | — | -| [`public bool Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.cancel { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L219) | Gets whether Escape requests canceling the current list workflow. | — | — | +| [`public readonly struct Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L167) | Carries frame-local list navigation intents over visible indices without owning objects or selection state. | — | — | +| [`public int Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.focusedIndex { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L192) | Gets the resulting visible focus index, or minus one for no focus. | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.focusChanged { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L196) | Gets whether the visible focus index changed. | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.selectionRequested { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L200) | Gets whether the caller should apply a domain selection operation. | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.extendRange { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L204) | Gets whether the selection should extend from its existing anchor. | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.additive { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L208) | Gets whether the product's primary modifier requests preserving other selected entries. | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.toggle { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L212) | Gets whether Space with the primary modifier requests toggling the focused entry. | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.activate { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L216) | Gets whether Enter requests activation of the focused entry. | — | — | +| [`public bool Inno.Editor.ImGui.ImGuiWidget.ListNavigationResult.cancel { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Selection.cs#L220) | Gets whether Escape requests canceling the current list workflow. | — | — | | [`public readonly struct Inno.Editor.ImGui.ImGuiWidget.TreeNodeDrawContext`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L464) | Provides the native geometry of a tree row while its custom content is being drawn. | — | — | | [`public float Inno.Editor.ImGui.ImGuiWidget.TreeNodeDrawContext.rowHeight { get; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L474) | Gets the actual native row height established for the current tree node. | — | — | | [`public readonly struct Inno.Editor.ImGui.ImGuiWidget.TreeNodeOptions`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L480) | Configures an interactive tree row. | — | — | @@ -2665,7 +2744,7 @@ static void DrawHelp() | [`public bool Inno.Editor.ImGui.ImGuiWidget.TreeNodeOptions.selected { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L500) | Gets whether the row is selected. | — | — | | [`public bool Inno.Editor.ImGui.ImGuiWidget.TreeNodeOptions.isLeaf { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L504) | Gets whether the row has no expandable children. | — | — | | [`public bool Inno.Editor.ImGui.ImGuiWidget.TreeNodeOptions.showBackground { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L508) | Gets whether a custom background is drawn behind an unselected row. | — | — | -| [`public System.Numerics.Vector4 Inno.Editor.ImGui.ImGuiWidget.TreeNodeOptions.backgroundColor { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L512) | Gets the custom background color used when is enabled. | — | — | +| [`public System.Numerics.Vector4 Inno.Editor.ImGui.ImGuiWidget.TreeNodeOptions.backgroundColor { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L512) | Gets the custom background color used when P:Inno.Editor.ImGui.ImGuiWidget.TreeNodeOptions.showBackground is enabled. | — | — | | [`public bool Inno.Editor.ImGui.ImGuiWidget.TreeNodeOptions.suppressHoverHighlight { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L516) | Gets whether the row keeps its configured background while hovered. | — | — | | [`public bool Inno.Editor.ImGui.ImGuiWidget.TreeNodeOptions.hideGuideLines { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L520) | Gets whether ancestor and branch guide lines are omitted for this row. | — | — | | [`public System.Action? Inno.Editor.ImGui.ImGuiWidget.TreeNodeOptions.drawViewportOverlay { get; init; }`](../../src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Tree.cs#L525) | Gets the callback that draws controls fixed to the current viewport without extending the tree's horizontal content boundary. | — | — | diff --git a/docs/editor/Inno.Editor.Interactions.md b/docs/editor/Inno.Editor.Interactions.md index c16af315..53cf73cb 100644 --- a/docs/editor/Inno.Editor.Interactions.md +++ b/docs/editor/Inno.Editor.Interactions.md @@ -825,6 +825,7 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 + @@ -968,55 +969,55 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 -| API 与源码 | 契约与参数 | 返回值 | 重要异常 | -| --- | --- | --- | --- | +| API | 职责与参数 | 返回语义 | 失败条件 | +|---|---|---|---| | [`public abstract class Inno.Editor.Interactions.EditorAction : System.IDisposable`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L8) | Defines one automatically discovered editor operation and owns its complete multi-frame lifecycle. | — | — | | [`public bool Inno.Editor.Interactions.EditorAction.isActive { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L17) | Gets whether the action currently owns an active multi-frame operation. | — | — | -| [`public virtual System.Type? Inno.Editor.Interactions.EditorAction.targetType { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L21) | Gets the required target type, or for a targetless action. | — | — | +| [`public virtual System.Type? Inno.Editor.Interactions.EditorAction.targetType { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L21) | Gets the required target type, or null for a targetless action. | — | — | | [`protected object? Inno.Editor.Interactions.EditorAction.activeTarget { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L71) | Resolves the active target afresh for this callback; null means the identity is unavailable. | — | — | | [`protected Inno.Editor.Core.EditorContext? Inno.Editor.Interactions.EditorAction.activeEditorContext { get; private set; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L75) | Gets the host-owned passive context of the active operation, or null after completion. | — | — | -| [`protected void Inno.Editor.Interactions.EditorAction.Activate(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L86) | Activates this action for a target and cancels any operation it previously owned.
`context`: The contextual request that starts the operation. | — | `System.ArgumentNullException`: Thrown when is . | +| [`protected void Inno.Editor.Interactions.EditorAction.Activate(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L86) | Activates this action for a target and cancels any operation it previously owned.
`context`: The contextual request that starts the operation. | — | `System.ArgumentNullException`: Thrown when context is null. | | [`protected void Inno.Editor.Interactions.EditorAction.Complete()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L99) | Completes the current operation and returns the action to its idle state. | — | — | | [`protected void Inno.Editor.Interactions.EditorAction.Cancel()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L113) | Cancels the current operation and returns the action to its idle state. | — | — | -| [`protected virtual Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorAction.Query(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L133) | Evaluates the action for the supplied context.
`context`: The editor, area, target, and optional argument for the query. | The current presentation and availability state. | — | -| [`protected abstract void Inno.Editor.Interactions.EditorAction.Execute(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L140) | Executes the action for the supplied context.
`context`: The editor, area, target, and optional argument for the operation. | — | — | -| [`protected virtual bool Inno.Editor.Interactions.EditorAction.Present(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L150) | Presents an active action at the current target location.
`context`: The current presentation area and target. | when the action replaced the target's normal content; otherwise, . | — | +| [`protected virtual Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorAction.Query(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L133) | Evaluates the action for the supplied context.
`context`: The editor, area, target, and optional argument for the query. | The current presentation and availability state. | — | +| [`protected abstract void Inno.Editor.Interactions.EditorAction.Execute(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L140) | Executes the action for the supplied context.
`context`: The editor, area, target, and optional argument for the operation. | — | — | +| [`protected virtual bool Inno.Editor.Interactions.EditorAction.Present(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L150) | Presents an active action at the current target location.
`context`: The current presentation area and target. | true when the action replaced the target's normal content; otherwise, false. | — | | [`protected virtual void Inno.Editor.Interactions.EditorAction.OnCompleted()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L154) | Runs after an active operation completes successfully. | — | — | | [`protected virtual void Inno.Editor.Interactions.EditorAction.OnCancelled()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L161) | Runs after an active operation is cancelled. | — | — | | [`protected virtual void Inno.Editor.Interactions.EditorAction.OnPresentationLost()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L173) | Runs when this action's active target loses editor presentation focus. | — | — | | [`public void Inno.Editor.Interactions.EditorAction.Dispose()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L177) | Cancels active work and releases this action instance. | — | — | -| [`protected Inno.Editor.Interactions.EditorAction.EditorAction()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L8) | Inherited or compiler-provided contract. | — | — | -| [`public abstract class Inno.Editor.Interactions.EditorAction : Inno.Editor.Interactions.EditorAction`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L196) | Defines a target action that requires one strongly typed command argument.
`TTarget`: The target type accepted by the action.
`TArgument`: The command argument type accepted by the action. | — | — | +| [`protected Inno.Editor.Interactions.EditorAction.EditorAction()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L8) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public abstract class Inno.Editor.Interactions.EditorAction : Inno.Editor.Interactions.EditorAction`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L196) | Defines a target action that requires one strongly typed command argument.
`TTarget`: The target type accepted by the action.
`TArgument`: The command argument type accepted by the action. | — | — | | [`public override sealed System.Type Inno.Editor.Interactions.EditorAction.targetType { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L201) | Gets the concrete type handled by this extension implementation. | — | — | -| [`protected override sealed Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorAction.Query(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L213) | Evaluates the operation's current availability and presentation state.
`context`: The context that supplies state and services for this operation. | The validated editor action state that represents the completed operation. | — | -| [`protected override sealed void Inno.Editor.Interactions.EditorAction.Execute(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L223) | Applies the editor action to the supplied interaction context.
`context`: The context that supplies state and services for this operation. | — | — | -| [`protected override sealed bool Inno.Editor.Interactions.EditorAction.Present(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L242) | Presents this action through the current editor interaction surface.
`context`: The context that supplies state and services for this operation. | when the operation succeeds or its condition is satisfied; otherwise, . | — | -| [`protected virtual Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorAction.Query(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L252) | Evaluates the action for a typed target and argument.
`context`: The typed contextual request. | The current presentation and availability state. | — | -| [`protected abstract void Inno.Editor.Interactions.EditorAction.Execute(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L259) | Executes the action for a typed target and argument.
`context`: The typed contextual request. | — | — | -| [`protected virtual bool Inno.Editor.Interactions.EditorAction.Present(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L269) | Presents an active action for a typed target and argument.
`context`: The typed presentation request. | when content was presented. | — | -| [`protected Inno.Editor.Interactions.EditorAction.EditorAction()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L196) | Inherited or compiler-provided contract. | — | — | -| [`public abstract class Inno.Editor.Interactions.EditorArgumentAction : Inno.Editor.Interactions.EditorAction`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L291) | Defines a targetless editor action that requires one strongly typed command argument.
`TArgument`: The command argument type accepted by the action. | — | — | -| [`protected override sealed Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorArgumentAction.Query(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L304) | Evaluates the operation's current availability and presentation state.
`context`: The context that supplies state and services for this operation. | The validated editor action state that represents the completed operation. | — | -| [`protected override sealed void Inno.Editor.Interactions.EditorArgumentAction.Execute(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L312) | Applies the editor action to the supplied interaction context.
`context`: The context that supplies state and services for this operation. | — | — | -| [`protected virtual Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorArgumentAction.Query(Inno.Editor.Interactions.EditorActionArgumentContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L331) | Evaluates the action for a typed argument.
`context`: The typed contextual request. | The current presentation and availability state. | — | -| [`protected abstract void Inno.Editor.Interactions.EditorArgumentAction.Execute(Inno.Editor.Interactions.EditorActionArgumentContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L338) | Executes the action for a typed argument.
`context`: The typed contextual request. | — | — | -| [`protected Inno.Editor.Interactions.EditorArgumentAction.EditorArgumentAction()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L291) | Inherited or compiler-provided contract. | — | — | -| [`public abstract class Inno.Editor.Interactions.EditorPresentationAction : Inno.Editor.Interactions.EditorAction`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L350) | Defines a target action with a typed presentation-only argument.
`TTarget`: The target type accepted by the action.
`TPresentation`: The presentation data type. | — | — | -| [`protected override sealed bool Inno.Editor.Interactions.EditorPresentationAction.Present(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L361) | Presents this action through the current editor interaction surface.
`context`: The context that supplies state and services for this operation. | when the operation succeeds or its condition is satisfied; otherwise, . | — | -| [`protected abstract bool Inno.Editor.Interactions.EditorPresentationAction.Present(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L372) | Presents active content using strongly typed presentation data.
`context`: The typed presentation request. | when content was presented. | — | -| [`protected Inno.Editor.Interactions.EditorPresentationAction.EditorPresentationAction()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L350) | Inherited or compiler-provided contract. | — | — | -| [`public abstract class Inno.Editor.Interactions.EditorAction : Inno.Editor.Interactions.EditorAction`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L381) | Defines a discoverable action whose target must be assignable to a specific reference type.
`TTarget`: The target type accepted by the action. | — | — | +| [`protected override sealed Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorAction.Query(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L213) | Evaluates the operation's current availability and presentation state.
`context`: The context that supplies state and services for this operation. | The validated editor action state that represents the completed operation. | — | +| [`protected override sealed void Inno.Editor.Interactions.EditorAction.Execute(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L223) | Applies the editor action to the supplied interaction context.
`context`: The context that supplies state and services for this operation. | — | — | +| [`protected override sealed bool Inno.Editor.Interactions.EditorAction.Present(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L242) | Presents this action through the current editor interaction surface.
`context`: The context that supplies state and services for this operation. | true when the operation succeeds or its condition is satisfied; otherwise, false. | — | +| [`protected virtual Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorAction.Query(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L252) | Evaluates the action for a typed target and argument.
`context`: The typed contextual request. | The current presentation and availability state. | — | +| [`protected abstract void Inno.Editor.Interactions.EditorAction.Execute(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L259) | Executes the action for a typed target and argument.
`context`: The typed contextual request. | — | — | +| [`protected virtual bool Inno.Editor.Interactions.EditorAction.Present(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L269) | Presents an active action for a typed target and argument.
`context`: The typed presentation request. | true when content was presented. | — | +| [`protected Inno.Editor.Interactions.EditorAction.EditorAction()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L196) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public abstract class Inno.Editor.Interactions.EditorArgumentAction : Inno.Editor.Interactions.EditorAction`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L291) | Defines a targetless editor action that requires one strongly typed command argument.
`TArgument`: The command argument type accepted by the action. | — | — | +| [`protected override sealed Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorArgumentAction.Query(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L304) | Evaluates the operation's current availability and presentation state.
`context`: The context that supplies state and services for this operation. | The validated editor action state that represents the completed operation. | — | +| [`protected override sealed void Inno.Editor.Interactions.EditorArgumentAction.Execute(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L312) | Applies the editor action to the supplied interaction context.
`context`: The context that supplies state and services for this operation. | — | — | +| [`protected virtual Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorArgumentAction.Query(Inno.Editor.Interactions.EditorActionArgumentContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L331) | Evaluates the action for a typed argument.
`context`: The typed contextual request. | The current presentation and availability state. | — | +| [`protected abstract void Inno.Editor.Interactions.EditorArgumentAction.Execute(Inno.Editor.Interactions.EditorActionArgumentContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L338) | Executes the action for a typed argument.
`context`: The typed contextual request. | — | — | +| [`protected Inno.Editor.Interactions.EditorArgumentAction.EditorArgumentAction()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L291) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public abstract class Inno.Editor.Interactions.EditorPresentationAction : Inno.Editor.Interactions.EditorAction`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L350) | Defines a target action with a typed presentation-only argument.
`TTarget`: The target type accepted by the action.
`TPresentation`: The presentation data type. | — | — | +| [`protected override sealed bool Inno.Editor.Interactions.EditorPresentationAction.Present(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L361) | Presents this action through the current editor interaction surface.
`context`: The context that supplies state and services for this operation. | true when the operation succeeds or its condition is satisfied; otherwise, false. | — | +| [`protected abstract bool Inno.Editor.Interactions.EditorPresentationAction.Present(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L372) | Presents active content using strongly typed presentation data.
`context`: The typed presentation request. | true when content was presented. | — | +| [`protected Inno.Editor.Interactions.EditorPresentationAction.EditorPresentationAction()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L350) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public abstract class Inno.Editor.Interactions.EditorAction : Inno.Editor.Interactions.EditorAction`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L381) | Defines a discoverable action whose target must be assignable to a specific reference type.
`TTarget`: The target type accepted by the action. | — | — | | [`public override sealed System.Type Inno.Editor.Interactions.EditorAction.targetType { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L386) | Gets the concrete type handled by this extension implementation. | — | — | -| [`protected override sealed Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorAction.Query(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L397) | Evaluates the operation's current availability and presentation state.
`context`: The context that supplies state and services for this operation. | The validated editor action state that represents the completed operation. | — | -| [`protected override sealed void Inno.Editor.Interactions.EditorAction.Execute(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L409) | Applies the editor action to the supplied interaction context.
`context`: The context that supplies state and services for this operation. | — | — | -| [`protected override sealed bool Inno.Editor.Interactions.EditorAction.Present(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L429) | Presents this action through the current editor interaction surface.
`context`: The context that supplies state and services for this operation. | when the operation succeeds or its condition is satisfied; otherwise, . | — | -| [`protected virtual Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorAction.Query(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L444) | Evaluates the action for a strongly typed target.
`context`: The contextual request containing the typed target. | The current presentation and availability state. | — | -| [`protected abstract void Inno.Editor.Interactions.EditorAction.Execute(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L451) | Executes the action for a strongly typed target.
`context`: The contextual request containing the typed target. | — | — | -| [`protected virtual bool Inno.Editor.Interactions.EditorAction.Present(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L461) | Presents an active action for a strongly typed target.
`context`: The current presentation request containing the typed target. | when content was presented; otherwise, . | — | -| [`protected Inno.Editor.Interactions.EditorAction.EditorAction()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L381) | Inherited or compiler-provided contract. | — | — | +| [`protected override sealed Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorAction.Query(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L397) | Evaluates the operation's current availability and presentation state.
`context`: The context that supplies state and services for this operation. | The validated editor action state that represents the completed operation. | — | +| [`protected override sealed void Inno.Editor.Interactions.EditorAction.Execute(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L409) | Applies the editor action to the supplied interaction context.
`context`: The context that supplies state and services for this operation. | — | — | +| [`protected override sealed bool Inno.Editor.Interactions.EditorAction.Present(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L429) | Presents this action through the current editor interaction surface.
`context`: The context that supplies state and services for this operation. | true when the operation succeeds or its condition is satisfied; otherwise, false. | — | +| [`protected virtual Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorAction.Query(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L444) | Evaluates the action for a strongly typed target.
`context`: The contextual request containing the typed target. | The current presentation and availability state. | — | +| [`protected abstract void Inno.Editor.Interactions.EditorAction.Execute(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L451) | Executes the action for a strongly typed target.
`context`: The contextual request containing the typed target. | — | — | +| [`protected virtual bool Inno.Editor.Interactions.EditorAction.Present(Inno.Editor.Interactions.EditorActionContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L461) | Presents an active action for a strongly typed target.
`context`: The current presentation request containing the typed target. | true when content was presented; otherwise, false. | — | +| [`protected Inno.Editor.Interactions.EditorAction.EditorAction()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorAction.cs#L381) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public sealed class Inno.Editor.Interactions.EditorActionAttribute : System.Attribute`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionAttribute.cs#L9) | Registers an editor action for automatic discovery and dispatch. | — | — | -| [`public Inno.Editor.Interactions.EditorActionAttribute.EditorActionAttribute(string action, int priority = 0)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionAttribute.cs#L23) | Creates an action registration available from every area.
`action`: The stable semantic action name.
`priority`: The tie-breaking priority used after target specificity. | — | `System.ArgumentException`: Thrown when is empty. | -| [`public Inno.Editor.Interactions.EditorActionAttribute.EditorActionAttribute(string action, string area, int priority = 0)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionAttribute.cs#L46) | Creates an action registration restricted to one exact area.
`action`: The stable semantic action name.
`area`: The exact area, or an empty string for every area.
`priority`: The tie-breaking priority. | — | `System.ArgumentException`: Thrown when is empty. | +| [`public Inno.Editor.Interactions.EditorActionAttribute.EditorActionAttribute(string action, int priority = 0)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionAttribute.cs#L23) | Creates an action registration available from every area.
`action`: The stable semantic action name.
`priority`: The tie-breaking priority used after target specificity. | — | `System.ArgumentException`: Thrown when action is empty. | +| [`public Inno.Editor.Interactions.EditorActionAttribute.EditorActionAttribute(string action, string area, int priority = 0)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionAttribute.cs#L46) | Creates an action registration restricted to one exact area.
`action`: The stable semantic action name.
`area`: The exact area, or an empty string for every area.
`priority`: The tie-breaking priority. | — | `System.ArgumentException`: Thrown when action is empty. | | [`public string Inno.Editor.Interactions.EditorActionAttribute.action { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionAttribute.cs#L61) | Gets the stable action name. | — | — | | [`public string Inno.Editor.Interactions.EditorActionAttribute.area { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionAttribute.cs#L66) | Gets the optional exact interaction area. | — | — | | [`public int Inno.Editor.Interactions.EditorActionAttribute.priority { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionAttribute.cs#L71) | Gets the tie-breaking priority. | — | — | @@ -1026,15 +1027,15 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`public Inno.Editor.Interactions.IEditorHistory Inno.Editor.Interactions.EditorActionContext.history { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionContext.cs#L60) | Gets the transactional history used to record reversible mutations performed by this action. | — | — | | [`public string Inno.Editor.Interactions.EditorActionContext.area { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionContext.cs#L64) | Gets the stable interaction area. | — | — | | [`public object? Inno.Editor.Interactions.EditorActionContext.target { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionContext.cs#L68) | Gets the contextual action target. | — | — | -| [`public sealed class Inno.Editor.Interactions.EditorActionContext : Inno.Editor.Interactions.EditorActionContext`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionContext.cs#L81) | Provides a strongly typed target to an editor action implementation.
`TTarget`: The target type required by the action. | — | — | +| [`public sealed class Inno.Editor.Interactions.EditorActionContext : Inno.Editor.Interactions.EditorActionContext`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionContext.cs#L81) | Provides a strongly typed target to an editor action implementation.
`TTarget`: The target type required by the action. | — | — | | [`public TTarget Inno.Editor.Interactions.EditorActionContext.target { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionContext.cs#L94) | Gets the strongly typed action target. | — | — | -| [`public sealed class Inno.Editor.Interactions.EditorActionContext : Inno.Editor.Interactions.EditorActionContext`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionContext.cs#L106) | Provides a strongly typed target and action argument to an editor action.
`TTarget`: The target type required by the action.
`TArgument`: The action argument type required by the action. | — | — | +| [`public sealed class Inno.Editor.Interactions.EditorActionContext : Inno.Editor.Interactions.EditorActionContext`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionContext.cs#L106) | Provides a strongly typed target and action argument to an editor action.
`TTarget`: The target type required by the action.
`TArgument`: The action argument type required by the action. | — | — | | [`public TTarget Inno.Editor.Interactions.EditorActionContext.target { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionContext.cs#L121) | Gets the strongly typed action target. | — | — | | [`public TArgument Inno.Editor.Interactions.EditorActionContext.argument { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionContext.cs#L125) | Gets the strongly typed action argument. | — | — | -| [`public sealed class Inno.Editor.Interactions.EditorActionArgumentContext : Inno.Editor.Interactions.EditorActionContext`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionContext.cs#L134) | Provides a strongly typed action argument to a targetless editor action.
`TArgument`: The action argument type required by the action. | — | — | +| [`public sealed class Inno.Editor.Interactions.EditorActionArgumentContext : Inno.Editor.Interactions.EditorActionContext`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionContext.cs#L134) | Provides a strongly typed action argument to a targetless editor action.
`TArgument`: The action argument type required by the action. | — | — | | [`public TArgument Inno.Editor.Interactions.EditorActionArgumentContext.argument { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionContext.cs#L147) | Gets the strongly typed action argument. | — | — | | [`public readonly record struct Inno.Editor.Interactions.EditorActionState : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L5) | Describes the current presentation and availability of an editor action. | — | — | -| [`public Inno.Editor.Interactions.EditorActionState.EditorActionState(bool isVisible, bool isEnabled, bool isChecked = false, string? displayName = null, string? unavailableReason = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L25) | Creates the contextual presentation state of an editor action.
`isVisible`: Whether the action should be included in the current presentation.
`isEnabled`: Whether the action can execute in the current context.
`isChecked`: Whether the action is currently presented as checked.
`displayName`: An optional contextual label that replaces the static placement label.
`unavailableReason`: A concise explanation shown when an otherwise visible action cannot execute. | — | — | +| [`public Inno.Editor.Interactions.EditorActionState.EditorActionState(bool isVisible, bool isEnabled, bool isChecked = false, string? displayName = null, string? unavailableReason = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L25) | Creates the contextual presentation state of an editor action.
`isVisible`: Whether the action should be included in the current presentation.
`isEnabled`: Whether the action can execute in the current context.
`isChecked`: Whether the action is currently presented as checked.
`displayName`: An optional contextual label that replaces the static placement label.
`unavailableReason`: A concise explanation shown when an otherwise visible action cannot execute. | — | — | | [`public bool Inno.Editor.Interactions.EditorActionState.isVisible { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L42) | Gets whether the action should be displayed. | — | — | | [`public bool Inno.Editor.Interactions.EditorActionState.isEnabled { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L46) | Gets whether the action can execute. | — | — | | [`public bool Inno.Editor.Interactions.EditorActionState.isChecked { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L50) | Gets whether the action is currently checked. | — | — | @@ -1044,42 +1045,42 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`public static Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorActionState.disabled { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L66) | Gets a visible but disabled action state. | — | — | | [`public static Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorActionState.hidden { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L70) | Gets a hidden action state. | — | — | | [`public override string Inno.Editor.Interactions.EditorActionState.ToString()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L5) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | -| [`public static bool Inno.Editor.Interactions.EditorActionState.operator !=(Inno.Editor.Interactions.EditorActionState left, Inno.Editor.Interactions.EditorActionState right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L5) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.Interactions.EditorActionState.operator ==(Inno.Editor.Interactions.EditorActionState left, Inno.Editor.Interactions.EditorActionState right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L5) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.Interactions.EditorActionState.operator !=(Inno.Editor.Interactions.EditorActionState left, Inno.Editor.Interactions.EditorActionState right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L5) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Interactions.EditorActionState.operator ==(Inno.Editor.Interactions.EditorActionState left, Inno.Editor.Interactions.EditorActionState right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L5) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.Interactions.EditorActionState.GetHashCode()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L5) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.Interactions.EditorActionState.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L5) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.Interactions.EditorActionState.Equals(Inno.Editor.Interactions.EditorActionState other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L5) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | +| [`public override bool Inno.Editor.Interactions.EditorActionState.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L5) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Interactions.EditorActionState.Equals(Inno.Editor.Interactions.EditorActionState other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorActionState.cs#L5) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | | [`public sealed class Inno.Editor.Interactions.EditorShortcutAttribute : System.Attribute`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorShortcutAttribute.cs#L11) | Associates an editor action with a keyboard shortcut. | — | — | -| [`public Inno.Editor.Interactions.EditorShortcutAttribute.EditorShortcutAttribute(Inno.Core.Input.KeyCode key, Inno.Core.Input.KeyModifier modifiers = Inno.Core.Input.KeyModifier.None, bool primary = false)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorShortcutAttribute.cs#L25) | Creates a shortcut that can be dispatched from any focused interaction surface.
`key`: The non-modifier key that triggers the action.
`modifiers`: The exact additional modifier keys required by the gesture.
`primary`: Whether the platform primary modifier, Command on macOS or Control elsewhere, is required. | — | — | -| [`public Inno.Editor.Interactions.EditorShortcutAttribute.EditorShortcutAttribute(string area, Inno.Core.Input.KeyCode key, Inno.Core.Input.KeyModifier modifiers = Inno.Core.Input.KeyModifier.None, bool primary = false)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorShortcutAttribute.cs#L49) | Creates a shortcut scoped to an exact interaction area.
`area`: The exact focused area that accepts the shortcut, or an empty string for any area.
`key`: The non-modifier key that triggers the action.
`modifiers`: The exact additional modifier keys required by the gesture.
`primary`: Whether the platform primary modifier, Command on macOS or Control elsewhere, is required. | — | — | +| [`public Inno.Editor.Interactions.EditorShortcutAttribute.EditorShortcutAttribute(Inno.Core.Input.KeyCode key, Inno.Core.Input.KeyModifier modifiers = Inno.Core.Input.KeyModifier.None, bool primary = false)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorShortcutAttribute.cs#L25) | Creates a shortcut that can be dispatched from any focused interaction surface.
`key`: The non-modifier key that triggers the action.
`modifiers`: The exact additional modifier keys required by the gesture.
`primary`: Whether the platform primary modifier, Command on macOS or Control elsewhere, is required. | — | — | +| [`public Inno.Editor.Interactions.EditorShortcutAttribute.EditorShortcutAttribute(string area, Inno.Core.Input.KeyCode key, Inno.Core.Input.KeyModifier modifiers = Inno.Core.Input.KeyModifier.None, bool primary = false)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorShortcutAttribute.cs#L49) | Creates a shortcut scoped to an exact interaction area.
`area`: The exact focused area that accepts the shortcut, or an empty string for any area.
`key`: The non-modifier key that triggers the action.
`modifiers`: The exact additional modifier keys required by the gesture.
`primary`: Whether the platform primary modifier, Command on macOS or Control elsewhere, is required. | — | — | | [`public string Inno.Editor.Interactions.EditorShortcutAttribute.area { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorShortcutAttribute.cs#L64) | Gets the optional exact interaction area. | — | — | | [`public Inno.Core.Input.KeyCode Inno.Editor.Interactions.EditorShortcutAttribute.key { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorShortcutAttribute.cs#L69) | Gets the shortcut key. | — | — | | [`public Inno.Core.Input.KeyModifier Inno.Editor.Interactions.EditorShortcutAttribute.modifiers { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorShortcutAttribute.cs#L74) | Gets additional shortcut modifiers. | — | — | | [`public bool Inno.Editor.Interactions.EditorShortcutAttribute.primary { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorShortcutAttribute.cs#L79) | Gets whether the platform primary modifier is required. | — | — | -| [`public readonly record struct Inno.Editor.Interactions.EditorValidationResult : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | Describes whether a requested editor operation is valid and carries a diagnostic when it is rejected.
`isValid`: Whether the requested operation may proceed.
`message`: The user-facing validation diagnostic, or an empty string for a valid result. | — | — | -| [`public Inno.Editor.Interactions.EditorValidationResult.EditorValidationResult(bool isValid, string message)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | Describes whether a requested editor operation is valid and carries a diagnostic when it is rejected.
`isValid`: Whether the requested operation may proceed.
`message`: The user-facing validation diagnostic, or an empty string for a valid result. | — | — | +| [`public readonly record struct Inno.Editor.Interactions.EditorValidationResult : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | Describes whether a requested editor operation is valid and carries a diagnostic when it is rejected.
`isValid`: Whether the requested operation may proceed.
`message`: The user-facing validation diagnostic, or an empty string for a valid result. | — | — | +| [`public Inno.Editor.Interactions.EditorValidationResult.EditorValidationResult(bool isValid, string message)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | Describes whether a requested editor operation is valid and carries a diagnostic when it is rejected.
`isValid`: Whether the requested operation may proceed.
`message`: The user-facing validation diagnostic, or an empty string for a valid result. | — | — | | [`public bool Inno.Editor.Interactions.EditorValidationResult.isValid { get; init; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L13) | Whether the requested operation may proceed. | — | — | | [`public string Inno.Editor.Interactions.EditorValidationResult.message { get; init; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L14) | The user-facing validation diagnostic, or an empty string for a valid result. | — | — | | [`public static Inno.Editor.Interactions.EditorValidationResult Inno.Editor.Interactions.EditorValidationResult.valid { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L19) | Gets a successful validation result. | — | — | -| [`public static Inno.Editor.Interactions.EditorValidationResult Inno.Editor.Interactions.EditorValidationResult.Invalid(string message)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L30) | Creates a failed validation result with a user-facing diagnostic.
`message`: The diagnostic that explains why the operation cannot proceed. | An invalid result containing the supplied diagnostic. | — | +| [`public static Inno.Editor.Interactions.EditorValidationResult Inno.Editor.Interactions.EditorValidationResult.Invalid(string message)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L30) | Creates a failed validation result with a user-facing diagnostic.
`message`: The diagnostic that explains why the operation cannot proceed. | An invalid result containing the supplied diagnostic. | — | | [`public override string Inno.Editor.Interactions.EditorValidationResult.ToString()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | -| [`public static bool Inno.Editor.Interactions.EditorValidationResult.operator !=(Inno.Editor.Interactions.EditorValidationResult left, Inno.Editor.Interactions.EditorValidationResult right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.Interactions.EditorValidationResult.operator ==(Inno.Editor.Interactions.EditorValidationResult left, Inno.Editor.Interactions.EditorValidationResult right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.Interactions.EditorValidationResult.operator !=(Inno.Editor.Interactions.EditorValidationResult left, Inno.Editor.Interactions.EditorValidationResult right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Interactions.EditorValidationResult.operator ==(Inno.Editor.Interactions.EditorValidationResult left, Inno.Editor.Interactions.EditorValidationResult right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.Interactions.EditorValidationResult.GetHashCode()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.Interactions.EditorValidationResult.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.Interactions.EditorValidationResult.Equals(Inno.Editor.Interactions.EditorValidationResult other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | -| [`public void Inno.Editor.Interactions.EditorValidationResult.Deconstruct(out bool isValid, out string message)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | Inherited or compiler-provided contract. | — | — | +| [`public override bool Inno.Editor.Interactions.EditorValidationResult.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Interactions.EditorValidationResult.Equals(Inno.Editor.Interactions.EditorValidationResult other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | +| [`public void Inno.Editor.Interactions.EditorValidationResult.Deconstruct(out bool isValid, out string message)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/EditorValidationResult.cs#L12) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public readonly record struct Inno.Editor.Interactions.HotKeyGesture : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L12) | Describes one keyboard gesture used to invoke an editor command. | — | — | -| [`public Inno.Editor.Interactions.HotKeyGesture.HotKeyGesture(Inno.Core.Input.KeyCode key, Inno.Core.Input.KeyModifier modifiers = Inno.Core.Input.KeyModifier.None, string superModifierLabel = "Super")`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L31) | Creates a keyboard gesture with an exact set of modifier keys after symbolic-key normalization.
`key`: The non-modifier key in the gesture.
`modifiers`: The modifier keys required by the gesture.
`superModifierLabel`: The display name of the Super modifier; the neutral name is used for explicitly constructed gestures. | — | `System.ArgumentException`: The modifier label is empty. | +| [`public Inno.Editor.Interactions.HotKeyGesture.HotKeyGesture(Inno.Core.Input.KeyCode key, Inno.Core.Input.KeyModifier modifiers = Inno.Core.Input.KeyModifier.None, string superModifierLabel = "Super")`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L31) | Creates a keyboard gesture with an exact set of modifier keys after symbolic-key normalization.
`key`: The non-modifier key in the gesture.
`modifiers`: The modifier keys required by the gesture.
`superModifierLabel`: The display name of the Super modifier; the neutral name is used for explicitly constructed gestures. | — | `System.ArgumentException`: The modifier label is empty. | | [`public Inno.Core.Input.KeyCode Inno.Editor.Interactions.HotKeyGesture.key { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L45) | Gets the main key. | — | — | | [`public Inno.Core.Input.KeyModifier Inno.Editor.Interactions.HotKeyGesture.modifiers { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L50) | Gets the required modifiers. | — | — | -| [`public static Inno.Editor.Interactions.HotKeyGesture Inno.Editor.Interactions.HotKeyGesture.Primary(Inno.Core.Input.KeyCode key, Inno.Editor.Core.EditorKeyboardPolicy keyboard, Inno.Core.Input.KeyModifier additionalModifiers = Inno.Core.Input.KeyModifier.None)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L67) | Creates a gesture that includes the product-selected primary modifier.
`key`: The non-modifier key in the gesture.
`keyboard`: The product-selected immutable keyboard policy.
`additionalModifiers`: Additional modifiers combined with the product-selected primary modifier. | A product-resolved keyboard gesture. | — | +| [`public static Inno.Editor.Interactions.HotKeyGesture Inno.Editor.Interactions.HotKeyGesture.Primary(Inno.Core.Input.KeyCode key, Inno.Editor.Core.EditorKeyboardPolicy keyboard, Inno.Core.Input.KeyModifier additionalModifiers = Inno.Core.Input.KeyModifier.None)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L67) | Creates a gesture that includes the product-selected primary modifier.
`key`: The non-modifier key in the gesture.
`keyboard`: The product-selected immutable keyboard policy.
`additionalModifiers`: Additional modifiers combined with the product-selected primary modifier. | A product-resolved keyboard gesture. | — | | [`public override string Inno.Editor.Interactions.HotKeyGesture.ToString()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L82) | Formats the gesture as a human-readable editor menu shortcut label. | A product-resolved textual representation of the gesture. | — | -| [`public static bool Inno.Editor.Interactions.HotKeyGesture.operator !=(Inno.Editor.Interactions.HotKeyGesture left, Inno.Editor.Interactions.HotKeyGesture right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L12) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.Interactions.HotKeyGesture.operator ==(Inno.Editor.Interactions.HotKeyGesture left, Inno.Editor.Interactions.HotKeyGesture right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L12) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.Interactions.HotKeyGesture.operator !=(Inno.Editor.Interactions.HotKeyGesture left, Inno.Editor.Interactions.HotKeyGesture right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L12) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Interactions.HotKeyGesture.operator ==(Inno.Editor.Interactions.HotKeyGesture left, Inno.Editor.Interactions.HotKeyGesture right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L12) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.Interactions.HotKeyGesture.GetHashCode()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L12) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.Interactions.HotKeyGesture.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L12) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.Interactions.HotKeyGesture.Equals(Inno.Editor.Interactions.HotKeyGesture other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L12) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | +| [`public override bool Inno.Editor.Interactions.HotKeyGesture.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L12) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Interactions.HotKeyGesture.Equals(Inno.Editor.Interactions.HotKeyGesture other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Actions/HotKeyGesture.cs#L12) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | | [`public sealed class Inno.Editor.Interactions.EditorDocumentContext`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentContext.cs#L10) | Stores only stable, reload-safe document identity and provider-owned draft parameters. | — | — | | [`public System.Guid Inno.Editor.Interactions.EditorDocumentContext.documentId { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentContext.cs#L30) | Gets the stable identity of this open source document. | — | — | | [`public System.Guid Inno.Editor.Interactions.EditorDocumentContext.assetId { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentContext.cs#L35) | Gets the persistent asset identity, or an empty value before the source has one. | — | — | @@ -1089,57 +1090,57 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`public bool Inno.Editor.Interactions.EditorDocumentContext.isDirty { get; internal set; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentContext.cs#L55) | Gets whether unsaved source or staged changes exist. | — | — | | [`public bool Inno.Editor.Interactions.EditorDocumentContext.isProviderAvailable { get; internal set; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentContext.cs#L60) | Gets whether a current-generation provider is available. | — | — | | [`public System.Collections.Generic.IReadOnlyDictionary Inno.Editor.Interactions.EditorDocumentContext.viewParameters { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentContext.cs#L65) | Gets an immutable snapshot of stable view parameters. | — | — | -| [`public void Inno.Editor.Interactions.EditorDocumentContext.SetViewParameter(string key, string value)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentContext.cs#L76) | Adds or replaces one stable scalar or JSON-formatted view parameter.
`key`: Stable provider-local parameter name.
`value`: Persistent scalar or JSON-formatted value. | — | — | -| [`public bool Inno.Editor.Interactions.EditorDocumentContext.TryGetViewParameter(string key, out string value)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentContext.cs#L97) | Tries to read one stable view parameter.
`key`: Stable provider-local parameter name.
`value`: Receives the stored value. | when the parameter exists. | — | +| [`public void Inno.Editor.Interactions.EditorDocumentContext.SetViewParameter(string key, string value)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentContext.cs#L76) | Adds or replaces one stable scalar or JSON-formatted view parameter.
`key`: Stable provider-local parameter name.
`value`: Persistent scalar or JSON-formatted value. | — | — | +| [`public bool Inno.Editor.Interactions.EditorDocumentContext.TryGetViewParameter(string key, out string value)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentContext.cs#L97) | Tries to read one stable view parameter.
`key`: Stable provider-local parameter name.
`value`: Receives the stored value. | true when the parameter exists. | — | | [`public abstract class Inno.Editor.Interactions.EditorDocumentProvider`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L8) | Implements one reloadable asset-document kind without owning presentation or source identity. | — | — | | [`public abstract string Inno.Editor.Interactions.EditorDocumentProvider.id { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L13) | Gets the globally stable provider identifier. | — | — | -| [`public abstract bool Inno.Editor.Interactions.EditorDocumentProvider.CanOpen(string assetPath)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L24) | Returns whether this provider can open the supplied project asset path.
`assetPath`: Normalized project asset path. | when the path is supported. | — | -| [`public virtual void Inno.Editor.Interactions.EditorDocumentProvider.Open(Inno.Editor.Interactions.EditorDocumentContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L32) | Initializes transient provider state for an opened or restored document.
`context`: Stable document context owned by the host. | — | — | -| [`public abstract bool Inno.Editor.Interactions.EditorDocumentProvider.Save(Inno.Editor.Interactions.EditorDocumentContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L43) | Saves all document changes to its asset source.
`context`: Stable document context owned by the host. | when the source is saved. | — | -| [`public virtual bool Inno.Editor.Interactions.EditorDocumentProvider.Apply(Inno.Editor.Interactions.EditorDocumentContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L54) | Applies staged authoring changes and saves their asset source.
`context`: Stable document context owned by the host. | when staged changes are applied. | — | -| [`public virtual bool Inno.Editor.Interactions.EditorDocumentProvider.Revert(Inno.Editor.Interactions.EditorDocumentContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L65) | Discards staged authoring changes and reloads the last saved source.
`context`: Stable document context owned by the host. | when the source is restored. | — | -| [`public virtual void Inno.Editor.Interactions.EditorDocumentProvider.Close(Inno.Editor.Interactions.EditorDocumentContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L77) | Releases transient provider state after a document closes.
`context`: Stable document context owned by the host. | — | — | -| [`protected Inno.Editor.Interactions.EditorDocumentProvider.EditorDocumentProvider()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L8) | Inherited or compiler-provided contract. | — | — | +| [`public abstract bool Inno.Editor.Interactions.EditorDocumentProvider.CanOpen(string assetPath)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L24) | Returns whether this provider can open the supplied project asset path.
`assetPath`: Normalized project asset path. | true when the path is supported. | — | +| [`public virtual void Inno.Editor.Interactions.EditorDocumentProvider.Open(Inno.Editor.Interactions.EditorDocumentContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L32) | Initializes transient provider state for an opened or restored document.
`context`: Stable document context owned by the host. | — | — | +| [`public abstract bool Inno.Editor.Interactions.EditorDocumentProvider.Save(Inno.Editor.Interactions.EditorDocumentContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L43) | Saves all document changes to its asset source.
`context`: Stable document context owned by the host. | true when the source is saved. | — | +| [`public virtual bool Inno.Editor.Interactions.EditorDocumentProvider.Apply(Inno.Editor.Interactions.EditorDocumentContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L54) | Applies staged authoring changes and saves their asset source.
`context`: Stable document context owned by the host. | true when staged changes are applied. | — | +| [`public virtual bool Inno.Editor.Interactions.EditorDocumentProvider.Revert(Inno.Editor.Interactions.EditorDocumentContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L65) | Discards staged authoring changes and reloads the last saved source.
`context`: Stable document context owned by the host. | true when the source is restored. | — | +| [`public virtual void Inno.Editor.Interactions.EditorDocumentProvider.Close(Inno.Editor.Interactions.EditorDocumentContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L77) | Releases transient provider state after a document closes.
`context`: Stable document context owned by the host. | — | — | +| [`protected Inno.Editor.Interactions.EditorDocumentProvider.EditorDocumentProvider()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/EditorDocumentProvider.cs#L8) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public enum Inno.Editor.Interactions.EditorDocumentCloseMode : int`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L9) | Selects how a dirty document responds to a close request. | — | — | | [`Inno.Editor.Interactions.EditorDocumentCloseMode.Cancel = 0`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L14) | Keeps the document open. | — | — | | [`Inno.Editor.Interactions.EditorDocumentCloseMode.Save = 1`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L18) | Closes the document after saving. | — | — | | [`Inno.Editor.Interactions.EditorDocumentCloseMode.Discard = 2`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L22) | Closes the document and discards unsaved state. | — | — | | [`public interface Inno.Editor.Interactions.IEditorDocumentService`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L28) | Owns single-instance editor documents independently from reloadable providers and presentation. | — | — | | [`System.Collections.Generic.IReadOnlyList Inno.Editor.Interactions.IEditorDocumentService.documents { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L33) | Gets the currently owned source documents. | — | — | -| [`System.IDisposable Inno.Editor.Interactions.IEditorDocumentService.RegisterProvider(Inno.Editor.Interactions.EditorDocumentProvider provider)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L44) | Registers one current-generation document provider.
`provider`: Provider instance to register. | A lease that detaches only this provider instance. | — | -| [`Inno.Editor.Interactions.EditorDocumentContext Inno.Editor.Interactions.IEditorDocumentService.Open(string assetPath, System.Guid assetId = default(System.Guid))`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L58) | Opens a document or returns its existing single instance.
`assetPath`: Project asset path.
`assetId`: Persistent asset identity when available. | The stable document context. | — | -| [`bool Inno.Editor.Interactions.IEditorDocumentService.UpdateAssetPath(System.Guid documentId, string assetPath)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L75) | Updates an open document's source location after an identity-preserving asset move, without changing history or focus.
`documentId`: Existing document identity.
`assetPath`: Current authoritative source location for the same persistent asset. | Whether the document exists. | — | -| [`void Inno.Editor.Interactions.IEditorDocumentService.SetDirty(System.Guid documentId, bool isDirty = true)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L89) | Updates a document's unsaved state without saving, discarding or changing its History.
`documentId`: Stable tab identity.
`isDirty`: Whether the provider's current draft differs from its saved baseline. | — | — | -| [`bool Inno.Editor.Interactions.IEditorDocumentService.Save(System.Guid documentId)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L103) | Saves one open document through its current provider.
`documentId`: Stable tab identity. | when the document is saved. | — | -| [`bool Inno.Editor.Interactions.IEditorDocumentService.SaveAll()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L111) | Saves every dirty open document. | when every dirty document is saved. | — | -| [`bool Inno.Editor.Interactions.IEditorDocumentService.Apply(System.Guid documentId)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L122) | Applies staged changes through the current provider.
`documentId`: Stable tab identity. | when changes are applied. | — | -| [`bool Inno.Editor.Interactions.IEditorDocumentService.Revert(System.Guid documentId)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L133) | Reverts staged changes through the current provider.
`documentId`: Stable tab identity. | when changes are reverted. | — | -| [`bool Inno.Editor.Interactions.IEditorDocumentService.Close(System.Guid documentId, Inno.Editor.Interactions.EditorDocumentCloseMode mode)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L147) | Closes one document using an explicit dirty-document decision.
`documentId`: Stable tab identity.
`mode`: Explicit close behavior. | when the document closed. | — | +| [`System.IDisposable Inno.Editor.Interactions.IEditorDocumentService.RegisterProvider(Inno.Editor.Interactions.EditorDocumentProvider provider)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L44) | Registers one current-generation document provider.
`provider`: Provider instance to register. | A lease that detaches only this provider instance. | — | +| [`Inno.Editor.Interactions.EditorDocumentContext Inno.Editor.Interactions.IEditorDocumentService.Open(string assetPath, System.Guid assetId = default(System.Guid))`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L58) | Opens a document or returns its existing single instance.
`assetPath`: Project asset path.
`assetId`: Persistent asset identity when available. | The stable document context. | — | +| [`bool Inno.Editor.Interactions.IEditorDocumentService.UpdateAssetPath(System.Guid documentId, string assetPath)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L75) | Updates an open document's source location after an identity-preserving asset move, without changing history or focus.
`documentId`: Existing document identity.
`assetPath`: Current authoritative source location for the same persistent asset. | Whether the document exists. | — | +| [`void Inno.Editor.Interactions.IEditorDocumentService.SetDirty(System.Guid documentId, bool isDirty = true)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L89) | Updates a document's unsaved state without saving, discarding or changing its History.
`documentId`: Stable tab identity.
`isDirty`: Whether the provider's current draft differs from its saved baseline. | — | — | +| [`bool Inno.Editor.Interactions.IEditorDocumentService.Save(System.Guid documentId)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L103) | Saves one open document through its current provider.
`documentId`: Stable tab identity. | true when the document is saved. | — | +| [`bool Inno.Editor.Interactions.IEditorDocumentService.SaveAll()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L111) | Saves every dirty open document. | true when every dirty document is saved. | — | +| [`bool Inno.Editor.Interactions.IEditorDocumentService.Apply(System.Guid documentId)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L122) | Applies staged changes through the current provider.
`documentId`: Stable tab identity. | true when changes are applied. | — | +| [`bool Inno.Editor.Interactions.IEditorDocumentService.Revert(System.Guid documentId)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L133) | Reverts staged changes through the current provider.
`documentId`: Stable tab identity. | true when changes are reverted. | — | +| [`bool Inno.Editor.Interactions.IEditorDocumentService.Close(System.Guid documentId, Inno.Editor.Interactions.EditorDocumentCloseMode mode)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Documents/IEditorDocumentService.cs#L147) | Closes one document using an explicit dirty-document decision.
`documentId`: Stable tab identity.
`mode`: Explicit close behavior. | true when the document closed. | — | | [`public sealed class Inno.Editor.Interactions.EditorDragContext`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDragContext.cs#L10) | Provides contextual state while beginning an editor drag. | — | — | -| [`public Inno.Editor.Interactions.EditorDragContext.EditorDragContext(Inno.Editor.Core.EditorContext editor, Inno.Editor.Interactions.EditorInteractions interactions, string area, Inno.Editor.Interactions.EditorDragData data)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDragContext.cs#L33) | Creates a managed editor drag request.
`editor`: The shared passive editor context.
`interactions`: The active interaction entry point.
`area`: The interaction area that produced the source.
`data`: The transient source identity and preview label. | — | `System.ArgumentNullException`: Thrown when , , or is .
`System.ArgumentException`: Thrown when is empty. | +| [`public Inno.Editor.Interactions.EditorDragContext.EditorDragContext(Inno.Editor.Core.EditorContext editor, Inno.Editor.Interactions.EditorInteractions interactions, string area, Inno.Editor.Interactions.EditorDragData data)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDragContext.cs#L33) | Creates a managed editor drag request.
`editor`: The shared passive editor context.
`interactions`: The active interaction entry point.
`area`: The interaction area that produced the source.
`data`: The transient source identity and preview label. | — | `System.ArgumentNullException`: Thrown when editor, interactions, or data is null.
`System.ArgumentException`: Thrown when area is empty. | | [`public Inno.Editor.Core.EditorContext Inno.Editor.Interactions.EditorDragContext.editor { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDragContext.cs#L49) | Gets the shared passive editor context. | — | — | | [`public Inno.Editor.Interactions.EditorInteractions Inno.Editor.Interactions.EditorDragContext.interactions { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDragContext.cs#L54) | Gets the active interaction entry point. | — | — | | [`public string Inno.Editor.Interactions.EditorDragContext.area { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDragContext.cs#L59) | Gets the source interaction area. | — | — | | [`public Inno.Editor.Interactions.EditorDragData Inno.Editor.Interactions.EditorDragContext.data { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDragContext.cs#L64) | Gets the managed drag data. | — | — | | [`public sealed class Inno.Editor.Interactions.EditorDragData`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDragData.cs#L10) | Contains the transient identity and preview label for one editor drag operation. | — | — | -| [`public Inno.Editor.Interactions.EditorDragData.EditorDragData(Inno.Core.Identity.IdentityObject source, string label)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDragData.cs#L27) | Creates drag data for a registered identity object.
`source`: The registered source object resolved again for each drop query and delivery.
`label`: The human-readable label used by drag previews. | — | `System.ArgumentNullException`: Thrown when is .
`System.InvalidOperationException`: Thrown when is not registered in a live identity domain. | +| [`public Inno.Editor.Interactions.EditorDragData.EditorDragData(Inno.Core.Identity.IdentityObject source, string label)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDragData.cs#L27) | Creates drag data for a registered identity object.
`source`: The registered source object resolved again for each drop query and delivery.
`label`: The human-readable label used by drag previews. | — | `System.ArgumentNullException`: Thrown when source is null.
`System.InvalidOperationException`: Thrown when source is not registered in a live identity domain. | | [`public Inno.Core.Identity.RuntimeIdentity Inno.Editor.Interactions.EditorDragData.sourceIdentity { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDragData.cs#L41) | Gets the domain-qualified transient identity written to the native drag protocol. | — | — | | [`public string Inno.Editor.Interactions.EditorDragData.label { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDragData.cs#L46) | Gets the drag preview label. | — | — | | [`public abstract class Inno.Editor.Interactions.EditorDrop`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L11) | Defines one discoverable typed editor drop operation. | — | — | | [`public abstract System.Type Inno.Editor.Interactions.EditorDrop.sourceType { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L16) | Gets the accepted drag source type. | — | — | | [`public abstract System.Type Inno.Editor.Interactions.EditorDrop.targetType { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L21) | Gets the accepted drop target type. | — | — | -| [`public abstract Inno.Editor.Interactions.EditorDropStatus Inno.Editor.Interactions.EditorDrop.Query(Inno.Editor.Interactions.EditorDropContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L32) | Evaluates whether the current managed source may be dropped on the supplied target.
`context`: The untyped source, target, surface, and requested placement. | The compatibility state and standard target visual. | — | -| [`public abstract Inno.Editor.Interactions.EditorDropResult Inno.Editor.Interactions.EditorDrop.Drop(Inno.Editor.Interactions.EditorDropContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L43) | Executes a delivered drop after a successful compatibility query.
`context`: The untyped source, target, surface, and requested placement. | The observable selection and reveal result of the operation. | — | -| [`protected Inno.Editor.Interactions.EditorDrop.EditorDrop()`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L11) | Inherited or compiler-provided contract. | — | — | -| [`public abstract class Inno.Editor.Interactions.EditorDrop where TSource : Inno.Core.Identity.IdentityObject where TTarget : class : Inno.Editor.Interactions.EditorDrop`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L55) | Defines a typed drop operation for one managed source and target pair.
`TSource`: The managed drag-source type accepted by the operation.
`TTarget`: The managed drop-target type accepted by the operation. | — | — | +| [`public abstract Inno.Editor.Interactions.EditorDropStatus Inno.Editor.Interactions.EditorDrop.Query(Inno.Editor.Interactions.EditorDropContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L32) | Evaluates whether the current managed source may be dropped on the supplied target.
`context`: The untyped source, target, surface, and requested placement. | The compatibility state and standard target visual. | — | +| [`public abstract Inno.Editor.Interactions.EditorDropResult Inno.Editor.Interactions.EditorDrop.Drop(Inno.Editor.Interactions.EditorDropContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L43) | Executes a delivered drop after a successful compatibility query.
`context`: The untyped source, target, surface, and requested placement. | The observable selection and reveal result of the operation. | — | +| [`protected Inno.Editor.Interactions.EditorDrop.EditorDrop()`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L11) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public abstract class Inno.Editor.Interactions.EditorDrop where TSource : Inno.Core.Identity.IdentityObject where TTarget : class : Inno.Editor.Interactions.EditorDrop`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L55) | Defines a typed drop operation for one managed source and target pair.
`TSource`: The managed drag-source type accepted by the operation.
`TTarget`: The managed drop-target type accepted by the operation. | — | — | | [`public override sealed System.Type Inno.Editor.Interactions.EditorDrop.sourceType { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L62) | Gets the concrete type handled by this extension implementation. | — | — | | [`public override sealed System.Type Inno.Editor.Interactions.EditorDrop.targetType { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L67) | Gets the concrete type handled by this extension implementation. | — | — | -| [`public override sealed Inno.Editor.Interactions.EditorDropStatus Inno.Editor.Interactions.EditorDrop.Query(Inno.Editor.Interactions.EditorDropContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L78) | Evaluates the operation's current availability and presentation state.
`context`: The context that supplies state and services for this operation. | The validated editor drop status that represents the completed operation. | — | -| [`public override sealed Inno.Editor.Interactions.EditorDropResult Inno.Editor.Interactions.EditorDrop.Drop(Inno.Editor.Interactions.EditorDropContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L95) | Validates and applies the current editor drag-and-drop interaction atomically.
`context`: The context that supplies state and services for this operation. | The validated editor drop result that represents the completed operation. | — | -| [`protected abstract Inno.Editor.Interactions.EditorDropStatus Inno.Editor.Interactions.EditorDrop.Query(Inno.Editor.Interactions.EditorDropContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L112) | Evaluates whether the strongly typed source may be dropped on the strongly typed target.
`context`: The typed source, target, surface, and requested placement. | The compatibility state and standard target visual. | — | -| [`protected abstract Inno.Editor.Interactions.EditorDropResult Inno.Editor.Interactions.EditorDrop.Drop(Inno.Editor.Interactions.EditorDropContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L123) | Executes a delivered drop for the strongly typed source and target.
`context`: The typed source, target, surface, and requested placement. | The observable selection and reveal result of the operation. | — | -| [`protected Inno.Editor.Interactions.EditorDrop.EditorDrop()`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L55) | Inherited or compiler-provided contract. | — | — | -| [`public sealed class Inno.Editor.Interactions.EditorDropContext where TSource : class where TTarget : class`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L135) | Provides strongly typed source and target values to a drop operation.
`TSource`: The managed drag-source type.
`TTarget`: The managed drop-target type. | — | — | +| [`public override sealed Inno.Editor.Interactions.EditorDropStatus Inno.Editor.Interactions.EditorDrop.Query(Inno.Editor.Interactions.EditorDropContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L78) | Evaluates the operation's current availability and presentation state.
`context`: The context that supplies state and services for this operation. | The validated editor drop status that represents the completed operation. | — | +| [`public override sealed Inno.Editor.Interactions.EditorDropResult Inno.Editor.Interactions.EditorDrop.Drop(Inno.Editor.Interactions.EditorDropContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L95) | Validates and applies the current editor drag-and-drop interaction atomically.
`context`: The context that supplies state and services for this operation. | The validated editor drop result that represents the completed operation. | — | +| [`protected abstract Inno.Editor.Interactions.EditorDropStatus Inno.Editor.Interactions.EditorDrop.Query(Inno.Editor.Interactions.EditorDropContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L112) | Evaluates whether the strongly typed source may be dropped on the strongly typed target.
`context`: The typed source, target, surface, and requested placement. | The compatibility state and standard target visual. | — | +| [`protected abstract Inno.Editor.Interactions.EditorDropResult Inno.Editor.Interactions.EditorDrop.Drop(Inno.Editor.Interactions.EditorDropContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L123) | Executes a delivered drop for the strongly typed source and target.
`context`: The typed source, target, surface, and requested placement. | The observable selection and reveal result of the operation. | — | +| [`protected Inno.Editor.Interactions.EditorDrop.EditorDrop()`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L55) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public sealed class Inno.Editor.Interactions.EditorDropContext where TSource : class where TTarget : class`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L135) | Provides strongly typed source and target values to a drop operation.
`TSource`: The managed drag-source type.
`TTarget`: The managed drop-target type. | — | — | | [`public Inno.Editor.Interactions.EditorDropContext Inno.Editor.Interactions.EditorDropContext.untyped { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L152) | Gets the untyped drop context. | — | — | | [`public Inno.Editor.Core.EditorContext Inno.Editor.Interactions.EditorDropContext.editor { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L157) | Gets the active editor context. | — | — | | [`public Inno.Editor.Interactions.EditorInteractions Inno.Editor.Interactions.EditorDropContext.interactions { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L162) | Gets the active interaction entry point. | — | — | @@ -1148,12 +1149,12 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`public TTarget Inno.Editor.Interactions.EditorDropContext.target { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L177) | Gets the typed drop target. | — | — | | [`public Inno.Editor.Interactions.EditorDropPlacement Inno.Editor.Interactions.EditorDropContext.placement { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDrop.cs#L182) | Gets the requested placement. | — | — | | [`public sealed class Inno.Editor.Interactions.EditorDropAttribute : System.Attribute`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropAttribute.cs#L9) | Registers a typed editor drop handler for an optional exact area. | — | — | -| [`public Inno.Editor.Interactions.EditorDropAttribute.EditorDropAttribute(int priority = 0)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropAttribute.cs#L17) | Creates a drop registration that can participate on any interaction surface.
`priority`: The tie-breaking priority used after source and target specificity. | — | — | -| [`public Inno.Editor.Interactions.EditorDropAttribute.EditorDropAttribute(string area, int priority = 0)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropAttribute.cs#L31) | Creates a drop registration scoped to an exact interaction area.
`area`: The exact target area handled by this registration, or an empty string for any area.
`priority`: The tie-breaking priority used after source and target specificity. | — | — | +| [`public Inno.Editor.Interactions.EditorDropAttribute.EditorDropAttribute(int priority = 0)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropAttribute.cs#L17) | Creates a drop registration that can participate on any interaction surface.
`priority`: The tie-breaking priority used after source and target specificity. | — | — | +| [`public Inno.Editor.Interactions.EditorDropAttribute.EditorDropAttribute(string area, int priority = 0)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropAttribute.cs#L31) | Creates a drop registration scoped to an exact interaction area.
`area`: The exact target area handled by this registration, or an empty string for any area.
`priority`: The tie-breaking priority used after source and target specificity. | — | — | | [`public string Inno.Editor.Interactions.EditorDropAttribute.area { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropAttribute.cs#L42) | Gets the optional exact interaction area. | — | — | | [`public int Inno.Editor.Interactions.EditorDropAttribute.priority { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropAttribute.cs#L47) | Gets the tie-breaking priority. | — | — | | [`public sealed class Inno.Editor.Interactions.EditorDropContext`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropContext.cs#L11) | Provides contextual state to an editor drop handler. | — | — | -| [`public Inno.Editor.Interactions.EditorDropContext.EditorDropContext(Inno.Editor.Core.EditorContext editor, Inno.Editor.Interactions.EditorInteractions interactions, string area, Inno.Editor.Interactions.EditorDragData data, Inno.Core.Identity.IdentityObject source, object target, Inno.Editor.Interactions.EditorDropPlacement placement = Inno.Editor.Interactions.EditorDropPlacement.None)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropContext.cs#L44) | Creates a managed drop request.
`editor`: The shared passive editor context.
`interactions`: The active interaction entry point.
`area`: The target interaction area.
`data`: The active identity-based drag data.
`source`: The live source resolved from for this operation only.
`target`: The managed target object exposed to typed handlers.
`placement`: The requested position relative to the target. | — | `System.ArgumentNullException`: Thrown when , , , , or is .
`System.ArgumentException`: Thrown when is empty. | +| [`public Inno.Editor.Interactions.EditorDropContext.EditorDropContext(Inno.Editor.Core.EditorContext editor, Inno.Editor.Interactions.EditorInteractions interactions, string area, Inno.Editor.Interactions.EditorDragData data, Inno.Core.Identity.IdentityObject source, object target, Inno.Editor.Interactions.EditorDropPlacement placement = Inno.Editor.Interactions.EditorDropPlacement.None)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropContext.cs#L44) | Creates a managed drop request.
`editor`: The shared passive editor context.
`interactions`: The active interaction entry point.
`area`: The target interaction area.
`data`: The active identity-based drag data.
`source`: The live source resolved from data for this operation only.
`target`: The managed target object exposed to typed handlers.
`placement`: The requested position relative to the target. | — | `System.ArgumentNullException`: Thrown when editor, interactions, data, source, or target is null.
`System.ArgumentException`: Thrown when area is empty. | | [`public Inno.Editor.Core.EditorContext Inno.Editor.Interactions.EditorDropContext.editor { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropContext.cs#L66) | Gets the shared passive editor context. | — | — | | [`public Inno.Editor.Interactions.EditorInteractions Inno.Editor.Interactions.EditorDropContext.interactions { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropContext.cs#L71) | Gets the active interaction entry point. | — | — | | [`public string Inno.Editor.Interactions.EditorDropContext.area { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropContext.cs#L76) | Gets the target interaction area. | — | — | @@ -1167,30 +1168,30 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`Inno.Editor.Interactions.EditorDropPlacement.Into = 2`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropPlacement.cs#L21) | Drop into the target. | — | — | | [`Inno.Editor.Interactions.EditorDropPlacement.After = 3`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropPlacement.cs#L26) | Insert after the target. | — | — | | [`public readonly record struct Inno.Editor.Interactions.EditorDropResult : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L6) | Describes the observable result of a completed editor drop. | — | — | -| [`public Inno.Editor.Interactions.EditorDropResult.EditorDropResult(bool accepted, object? selectionTarget = null, object? revealTarget = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L20) | Creates the observable result of a completed drop operation.
`accepted`: Whether the handler accepted and completed the drop.
`selectionTarget`: An optional object that the originating view should select.
`revealTarget`: An optional object that the originating view should reveal or expand. | — | — | +| [`public Inno.Editor.Interactions.EditorDropResult.EditorDropResult(bool accepted, object? selectionTarget = null, object? revealTarget = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L20) | Creates the observable result of a completed drop operation.
`accepted`: Whether the handler accepted and completed the drop.
`selectionTarget`: An optional object that the originating view should select.
`revealTarget`: An optional object that the originating view should reveal or expand. | — | — | | [`public bool Inno.Editor.Interactions.EditorDropResult.accepted { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L33) | Gets whether the drop was accepted. | — | — | | [`public object? Inno.Editor.Interactions.EditorDropResult.selectionTarget { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L38) | Gets the optional target that should become selected. | — | — | | [`public object? Inno.Editor.Interactions.EditorDropResult.revealTarget { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L43) | Gets the optional hierarchy target that should be revealed. | — | — | | [`public static Inno.Editor.Interactions.EditorDropResult Inno.Editor.Interactions.EditorDropResult.rejected { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L48) | Gets a rejected drop result. | — | — | -| [`public static Inno.Editor.Interactions.EditorDropResult Inno.Editor.Interactions.EditorDropResult.Accepted(object? selectionTarget = null, object? revealTarget = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L62) | Creates an accepted drop result with optional presentation requests.
`selectionTarget`: An optional object that the originating view should select.
`revealTarget`: An optional object that the originating view should reveal or expand. | An accepted drop result containing the supplied presentation requests. | — | +| [`public static Inno.Editor.Interactions.EditorDropResult Inno.Editor.Interactions.EditorDropResult.Accepted(object? selectionTarget = null, object? revealTarget = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L62) | Creates an accepted drop result with optional presentation requests.
`selectionTarget`: An optional object that the originating view should select.
`revealTarget`: An optional object that the originating view should reveal or expand. | An accepted drop result containing the supplied presentation requests. | — | | [`public override string Inno.Editor.Interactions.EditorDropResult.ToString()`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L6) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | -| [`public static bool Inno.Editor.Interactions.EditorDropResult.operator !=(Inno.Editor.Interactions.EditorDropResult left, Inno.Editor.Interactions.EditorDropResult right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L6) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.Interactions.EditorDropResult.operator ==(Inno.Editor.Interactions.EditorDropResult left, Inno.Editor.Interactions.EditorDropResult right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L6) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.Interactions.EditorDropResult.operator !=(Inno.Editor.Interactions.EditorDropResult left, Inno.Editor.Interactions.EditorDropResult right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L6) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Interactions.EditorDropResult.operator ==(Inno.Editor.Interactions.EditorDropResult left, Inno.Editor.Interactions.EditorDropResult right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L6) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.Interactions.EditorDropResult.GetHashCode()`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L6) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.Interactions.EditorDropResult.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L6) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.Interactions.EditorDropResult.Equals(Inno.Editor.Interactions.EditorDropResult other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L6) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | +| [`public override bool Inno.Editor.Interactions.EditorDropResult.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L6) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Interactions.EditorDropResult.Equals(Inno.Editor.Interactions.EditorDropResult other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropResult.cs#L6) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | | [`public readonly record struct Inno.Editor.Interactions.EditorDropStatus : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L6) | Describes whether and how a target accepts the active drag. | — | — | -| [`public Inno.Editor.Interactions.EditorDropStatus.EditorDropStatus(bool canDrop, Inno.Editor.Interactions.EditorDropVisual visual)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L17) | Creates the compatibility and presentation state of a potential drop target.
`canDrop`: Whether the active source may be delivered to the target.
`visual`: The standard visual requested for the target. | — | — | +| [`public Inno.Editor.Interactions.EditorDropStatus.EditorDropStatus(bool canDrop, Inno.Editor.Interactions.EditorDropVisual visual)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L17) | Creates the compatibility and presentation state of a potential drop target.
`canDrop`: Whether the active source may be delivered to the target.
`visual`: The standard visual requested for the target. | — | — | | [`public bool Inno.Editor.Interactions.EditorDropStatus.canDrop { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L28) | Gets whether the active source may be dropped. | — | — | | [`public Inno.Editor.Interactions.EditorDropVisual Inno.Editor.Interactions.EditorDropStatus.visual { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L33) | Gets the standard target visual. | — | — | | [`public static Inno.Editor.Interactions.EditorDropStatus Inno.Editor.Interactions.EditorDropStatus.rejected { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L38) | Gets an incompatible drop status. | — | — | -| [`public static Inno.Editor.Interactions.EditorDropStatus Inno.Editor.Interactions.EditorDropStatus.Accept(Inno.Editor.Interactions.EditorDropVisual visual = Inno.Editor.Interactions.EditorDropVisual.Highlight)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L49) | Creates an accepted drop status with the requested standard target visual.
`visual`: The standard visual drawn while the compatible source hovers the target. | An accepted drop status. | — | +| [`public static Inno.Editor.Interactions.EditorDropStatus Inno.Editor.Interactions.EditorDropStatus.Accept(Inno.Editor.Interactions.EditorDropVisual visual = Inno.Editor.Interactions.EditorDropVisual.Highlight)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L49) | Creates an accepted drop status with the requested standard target visual.
`visual`: The standard visual drawn while the compatible source hovers the target. | An accepted drop status. | — | | [`public override string Inno.Editor.Interactions.EditorDropStatus.ToString()`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L6) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | -| [`public static bool Inno.Editor.Interactions.EditorDropStatus.operator !=(Inno.Editor.Interactions.EditorDropStatus left, Inno.Editor.Interactions.EditorDropStatus right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L6) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.Interactions.EditorDropStatus.operator ==(Inno.Editor.Interactions.EditorDropStatus left, Inno.Editor.Interactions.EditorDropStatus right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L6) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.Interactions.EditorDropStatus.operator !=(Inno.Editor.Interactions.EditorDropStatus left, Inno.Editor.Interactions.EditorDropStatus right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L6) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Interactions.EditorDropStatus.operator ==(Inno.Editor.Interactions.EditorDropStatus left, Inno.Editor.Interactions.EditorDropStatus right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L6) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.Interactions.EditorDropStatus.GetHashCode()`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L6) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.Interactions.EditorDropStatus.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L6) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.Interactions.EditorDropStatus.Equals(Inno.Editor.Interactions.EditorDropStatus other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L6) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | +| [`public override bool Inno.Editor.Interactions.EditorDropStatus.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L6) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Interactions.EditorDropStatus.Equals(Inno.Editor.Interactions.EditorDropStatus other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropStatus.cs#L6) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | | [`public enum Inno.Editor.Interactions.EditorDropVisual : int`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropVisual.cs#L6) | Defines the standard visual used for a compatible drop target. | — | — | | [`Inno.Editor.Interactions.EditorDropVisual.None = 0`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropVisual.cs#L11) | No visual is drawn. | — | — | | [`Inno.Editor.Interactions.EditorDropVisual.Highlight = 1`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropVisual.cs#L16) | Draw a content highlight. | — | — | @@ -1198,27 +1199,27 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`Inno.Editor.Interactions.EditorDropVisual.InsertAfter = 3`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropVisual.cs#L26) | Draw an insertion line after the target. | — | — | | [`Inno.Editor.Interactions.EditorDropVisual.Disabled = 4`](../../src/composition/editor/framework/Inno.Editor.Interactions/DragDrop/EditorDropVisual.cs#L31) | Draw a disabled target visual. | — | — | | [`public sealed class Inno.Editor.Interactions.EditorEditGesture : System.IDisposable`](../../src/composition/editor/framework/Inno.Editor.Interactions/Editing/EditorEditGesture.cs#L7) | Owns one continuous edit transaction without retaining edited objects, setters or extension instances. | — | — | -| [`public Inno.Editor.Interactions.EditorEditGesture.EditorEditGesture(Inno.Editor.Interactions.IEditorHistory history, string name)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Editing/EditorEditGesture.cs#L25) | Begins an edit whose updates use the existing domain mutation and History protocols.
`history`: The authoritative History for the current editor session.
`name`: The operation name displayed by Undo and Redo after a successful commit. | — | `System.ArgumentNullException`: The History owner is null.
`System.InvalidOperationException`: History cannot begin a transaction in its current state. | +| [`public Inno.Editor.Interactions.EditorEditGesture.EditorEditGesture(Inno.Editor.Interactions.IEditorHistory history, string name)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Editing/EditorEditGesture.cs#L25) | Begins an edit whose updates use the existing domain mutation and History protocols.
`history`: The authoritative History for the current editor session.
`name`: The operation name displayed by Undo and Redo after a successful commit. | — | `System.ArgumentNullException`: The History owner is null.
`System.InvalidOperationException`: History cannot begin a transaction in its current state. | | [`public string Inno.Editor.Interactions.EditorEditGesture.mergeKey { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Editing/EditorEditGesture.cs#L37) | Gets the transient merge boundary shared only by updates within this gesture. | — | — | | [`public bool Inno.Editor.Interactions.EditorEditGesture.isActive { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Editing/EditorEditGesture.cs#L41) | Gets whether this gesture still owns an active transaction, including a rejected completion. | — | — | | [`public void Inno.Editor.Interactions.EditorEditGesture.Commit()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Editing/EditorEditGesture.cs#L49) | Commits the edit exactly once; rejected completion leaves the transaction available for retry. | — | `System.InvalidOperationException`: The gesture is finished or a nested transaction remains active. | | [`public Inno.Editor.Interactions.EditorHistoryResult Inno.Editor.Interactions.EditorEditGesture.Cancel()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Editing/EditorEditGesture.cs#L66) | Attempts to restore the state before the gesture without discarding a failed rollback. | The rollback outcome; a state-preserving failure keeps this gesture active for retry. | `System.InvalidOperationException`: The gesture is finished or a nested transaction remains active. | | [`public void Inno.Editor.Interactions.EditorEditGesture.Dispose()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Editing/EditorEditGesture.cs#L85) | Cancels an unfinished gesture and releases its ownership only after rollback succeeds. | — | `System.InvalidOperationException`: Rollback is blocked or a nested transaction remains active. | | [`public sealed class Inno.Editor.Interactions.EditorOperationPreparingEvent : Inno.Core.Events.Event`](../../src/composition/editor/framework/Inno.Editor.Interactions/Editing/EditorOperationPreparingEvent.cs#L10) | Synchronously closes transient edits before command execution or an extension-handler generation switch. | — | — | -| [`public Inno.Editor.Interactions.EditorOperationPreparingEvent.EditorOperationPreparingEvent()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Editing/EditorOperationPreparingEvent.cs#L10) | Inherited or compiler-provided contract. | — | — | +| [`public Inno.Editor.Interactions.EditorOperationPreparingEvent.EditorOperationPreparingEvent()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Editing/EditorOperationPreparingEvent.cs#L10) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public readonly record struct Inno.Editor.Interactions.EditorHistoryAvailability : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L8) | Describes whether a history change can currently move in one direction. | — | — | | [`public bool Inno.Editor.Interactions.EditorHistoryAvailability.isAvailable { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L21) | Gets whether the requested transition is currently available. | — | — | | [`public string Inno.Editor.Interactions.EditorHistoryAvailability.message { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L26) | Gets the diagnostic explaining why the transition is unavailable, or an empty string when available. | — | — | | [`public static Inno.Editor.Interactions.EditorHistoryAvailability Inno.Editor.Interactions.EditorHistoryAvailability.Available()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L34) | Creates an available transition result. | An availability value that permits the transition. | — | -| [`public static Inno.Editor.Interactions.EditorHistoryAvailability Inno.Editor.Interactions.EditorHistoryAvailability.Unavailable(string message)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L48) | Creates an unavailable transition result.
`message`: The non-empty diagnostic explaining why the transition is unavailable. | An availability value that rejects the transition. | `System.ArgumentException`: Thrown when is empty. | +| [`public static Inno.Editor.Interactions.EditorHistoryAvailability Inno.Editor.Interactions.EditorHistoryAvailability.Unavailable(string message)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L48) | Creates an unavailable transition result.
`message`: The non-empty diagnostic explaining why the transition is unavailable. | An availability value that rejects the transition. | `System.ArgumentException`: Thrown when message is empty. | | [`public override string Inno.Editor.Interactions.EditorHistoryAvailability.ToString()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L8) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | -| [`public static bool Inno.Editor.Interactions.EditorHistoryAvailability.operator !=(Inno.Editor.Interactions.EditorHistoryAvailability left, Inno.Editor.Interactions.EditorHistoryAvailability right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L8) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.Interactions.EditorHistoryAvailability.operator ==(Inno.Editor.Interactions.EditorHistoryAvailability left, Inno.Editor.Interactions.EditorHistoryAvailability right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L8) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.Interactions.EditorHistoryAvailability.operator !=(Inno.Editor.Interactions.EditorHistoryAvailability left, Inno.Editor.Interactions.EditorHistoryAvailability right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L8) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Interactions.EditorHistoryAvailability.operator ==(Inno.Editor.Interactions.EditorHistoryAvailability left, Inno.Editor.Interactions.EditorHistoryAvailability right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L8) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.Interactions.EditorHistoryAvailability.GetHashCode()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L8) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.Interactions.EditorHistoryAvailability.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L8) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.Interactions.EditorHistoryAvailability.Equals(Inno.Editor.Interactions.EditorHistoryAvailability other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L8) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | +| [`public override bool Inno.Editor.Interactions.EditorHistoryAvailability.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L8) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Interactions.EditorHistoryAvailability.Equals(Inno.Editor.Interactions.EditorHistoryAvailability other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryAvailability.cs#L8) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | | [`public sealed class Inno.Editor.Interactions.EditorHistoryChange : System.IDisposable`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryChange.cs#L8) | Describes one neutral reload-safe mutation interpreted by an attribute-discovered history handler. | — | — | -| [`public Inno.Editor.Interactions.EditorHistoryChange.EditorHistoryChange(string kind, Inno.Editor.Interactions.EditorHistoryPayload payload, string? mergeKey = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryChange.cs#L30) | Creates a neutral history change.
`kind`: The stable globally unique handler protocol identifier.
`payload`: The immutable neutral payload interpreted by the handler.
`mergeKey`: An optional stable key used by the handler to merge adjacent changes. | — | `System.ArgumentException`: Thrown when is empty.
`System.ArgumentNullException`: Thrown when is . | +| [`public Inno.Editor.Interactions.EditorHistoryChange.EditorHistoryChange(string kind, Inno.Editor.Interactions.EditorHistoryPayload payload, string? mergeKey = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryChange.cs#L30) | Creates a neutral history change.
`kind`: The stable globally unique handler protocol identifier.
`payload`: The immutable neutral payload interpreted by the handler.
`mergeKey`: An optional stable key used by the handler to merge adjacent changes. | — | `System.ArgumentException`: Thrown when kind is empty.
`System.ArgumentNullException`: Thrown when payload is null. | | [`public string Inno.Editor.Interactions.EditorHistoryChange.kind { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryChange.cs#L44) | Gets the stable globally unique handler protocol identifier. | — | — | | [`public Inno.Editor.Interactions.EditorHistoryPayload Inno.Editor.Interactions.EditorHistoryChange.payload { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryChange.cs#L49) | Gets the immutable neutral payload interpreted by the active handler generation. | — | — | | [`public string? Inno.Editor.Interactions.EditorHistoryChange.mergeKey { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryChange.cs#L54) | Gets the optional stable key used to merge adjacent changes to the same logical value. | — | — | @@ -1230,13 +1231,13 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`Inno.Editor.Interactions.EditorHistoryDirection.Undo = 0`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryDirection.cs#L11) | Restores the state that existed before the change was committed. | — | — | | [`Inno.Editor.Interactions.EditorHistoryDirection.Redo = 1`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryDirection.cs#L16) | Restores the state produced by the committed change. | — | — | | [`public abstract class Inno.Editor.Interactions.EditorHistoryHandler`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryHandler.cs#L8) | Interprets neutral editor history payloads for one current-generation feature protocol. | — | — | -| [`protected abstract Inno.Editor.Interactions.EditorHistoryAvailability Inno.Editor.Interactions.EditorHistoryHandler.Query(Inno.Editor.Interactions.EditorHistoryContext context, Inno.Editor.Interactions.EditorHistoryChange change, Inno.Editor.Interactions.EditorHistoryDirection direction)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryHandler.cs#L25) | Determines whether a neutral change can currently transition in the requested direction.
`context`: The current-generation editor services.
`change`: The neutral history change.
`direction`: The requested Undo or Redo direction. | The current transition availability. | — | -| [`protected abstract Inno.Editor.Interactions.EditorHistoryResult Inno.Editor.Interactions.EditorHistoryHandler.Apply(Inno.Editor.Interactions.EditorHistoryContext context, Inno.Editor.Interactions.EditorHistoryChange change, Inno.Editor.Interactions.EditorHistoryDirection direction)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryHandler.cs#L46) | Atomically applies a neutral history change in the requested direction.
`context`: The current-generation editor services.
`change`: The neutral history change.
`direction`: The requested Undo or Redo direction. | The transition result. A failure must leave the feature in its original state. | — | -| [`protected virtual bool Inno.Editor.Interactions.EditorHistoryHandler.TryMerge(Inno.Editor.Interactions.EditorHistoryChange older, Inno.Editor.Interactions.EditorHistoryChange newer, out Inno.Editor.Interactions.EditorHistoryChange? merged)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryHandler.cs#L67) | Attempts to merge two adjacent changes to the same logical value.
`older`: The existing older history change.
`newer`: The newly recorded adjacent history change.
`merged`: The independently owned merged change when successful. | when replaces both input changes. | — | -| [`protected static Inno.Editor.Interactions.EditorHistoryResult Inno.Editor.Interactions.EditorHistoryHandler.StateIntegrityFailure(string message)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryHandler.cs#L85) | Creates a failed result for a transition whose compensation also failed.
`message`: The diagnostic containing both the transition and compensation failures. | A failure that faults the owning history. | — | -| [`protected Inno.Editor.Interactions.EditorHistoryHandler.EditorHistoryHandler()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryHandler.cs#L8) | Inherited or compiler-provided contract. | — | — | +| [`protected abstract Inno.Editor.Interactions.EditorHistoryAvailability Inno.Editor.Interactions.EditorHistoryHandler.Query(Inno.Editor.Interactions.EditorHistoryContext context, Inno.Editor.Interactions.EditorHistoryChange change, Inno.Editor.Interactions.EditorHistoryDirection direction)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryHandler.cs#L25) | Determines whether a neutral change can currently transition in the requested direction.
`context`: The current-generation editor services.
`change`: The neutral history change.
`direction`: The requested Undo or Redo direction. | The current transition availability. | — | +| [`protected abstract Inno.Editor.Interactions.EditorHistoryResult Inno.Editor.Interactions.EditorHistoryHandler.Apply(Inno.Editor.Interactions.EditorHistoryContext context, Inno.Editor.Interactions.EditorHistoryChange change, Inno.Editor.Interactions.EditorHistoryDirection direction)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryHandler.cs#L46) | Atomically applies a neutral history change in the requested direction.
`context`: The current-generation editor services.
`change`: The neutral history change.
`direction`: The requested Undo or Redo direction. | The transition result. A failure must leave the feature in its original state. | — | +| [`protected virtual bool Inno.Editor.Interactions.EditorHistoryHandler.TryMerge(Inno.Editor.Interactions.EditorHistoryChange older, Inno.Editor.Interactions.EditorHistoryChange newer, out Inno.Editor.Interactions.EditorHistoryChange? merged)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryHandler.cs#L67) | Attempts to merge two adjacent changes to the same logical value.
`older`: The existing older history change.
`newer`: The newly recorded adjacent history change.
`merged`: The independently owned merged change when successful. | true when merged replaces both input changes. | — | +| [`protected static Inno.Editor.Interactions.EditorHistoryResult Inno.Editor.Interactions.EditorHistoryHandler.StateIntegrityFailure(string message)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryHandler.cs#L85) | Creates a failed result for a transition whose compensation also failed.
`message`: The diagnostic containing both the transition and compensation failures. | A failure that faults the owning history. | — | +| [`protected Inno.Editor.Interactions.EditorHistoryHandler.EditorHistoryHandler()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryHandler.cs#L8) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public sealed class Inno.Editor.Interactions.EditorHistoryHandlerAttribute : System.Attribute`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryHandlerAttribute.cs#L9) | Registers a stateless editor history handler for one stable change protocol. | — | — | -| [`public Inno.Editor.Interactions.EditorHistoryHandlerAttribute.EditorHistoryHandlerAttribute(string kind)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryHandlerAttribute.cs#L20) | Creates a history handler registration.
`kind`: The stable globally unique change protocol identifier. | — | `System.ArgumentException`: Thrown when is empty. | +| [`public Inno.Editor.Interactions.EditorHistoryHandlerAttribute.EditorHistoryHandlerAttribute(string kind)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryHandlerAttribute.cs#L20) | Creates a history handler registration.
`kind`: The stable globally unique change protocol identifier. | — | `System.ArgumentException`: Thrown when kind is empty. | | [`public string Inno.Editor.Interactions.EditorHistoryHandlerAttribute.kind { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryHandlerAttribute.cs#L29) | Gets the stable globally unique change protocol identifier. | — | — | | [`public sealed class Inno.Editor.Interactions.EditorHistoryOptions`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryOptions.cs#L8) | Configures retention and payload storage for one editor history. | — | — | | [`public int Inno.Editor.Interactions.EditorHistoryOptions.maxEntries { get; init; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryOptions.cs#L13) | Gets or initializes the maximum number of committed top-level entries retained in memory. | — | — | @@ -1244,11 +1245,11 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`public long Inno.Editor.Interactions.EditorHistoryOptions.maxDiskBytes { get; init; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryOptions.cs#L23) | Gets or initializes the maximum payload bytes retained in the temporary disk store. | — | — | | [`public int Inno.Editor.Interactions.EditorHistoryOptions.inlinePayloadThreshold { get; init; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryOptions.cs#L28) | Gets or initializes the payload size at which immutable bytes are moved to the temporary disk store. | — | — | | [`public string? Inno.Editor.Interactions.EditorHistoryOptions.cacheDirectory { get; init; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryOptions.cs#L33) | Gets or initializes the optional directory that owns temporary history payloads for this editor session. | — | — | -| [`public Inno.Editor.Interactions.EditorHistoryOptions.EditorHistoryOptions()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryOptions.cs#L8) | Inherited or compiler-provided contract. | — | — | +| [`public Inno.Editor.Interactions.EditorHistoryOptions.EditorHistoryOptions()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryOptions.cs#L8) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public sealed class Inno.Editor.Interactions.EditorHistoryPayload : System.IDisposable`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryPayload.cs#L9) | Owns immutable neutral bytes used by a reload-safe editor history change. | — | — | | [`public long Inno.Editor.Interactions.EditorHistoryPayload.length { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryPayload.cs#L35) | Gets the number of immutable bytes represented by this payload. | — | — | | [`public bool Inno.Editor.Interactions.EditorHistoryPayload.isStoredOnDisk { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryPayload.cs#L40) | Gets whether the payload is retained in the temporary disk store instead of resident memory. | — | — | -| [`public static Inno.Editor.Interactions.EditorHistoryPayload Inno.Editor.Interactions.EditorHistoryPayload.FromBytes(System.ReadOnlySpan bytes)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryPayload.cs#L55) | Creates an immutable history payload by copying the supplied bytes.
`bytes`: The neutral bytes to retain for future Undo and Redo transitions. | A new independently owned payload. | — | +| [`public static Inno.Editor.Interactions.EditorHistoryPayload Inno.Editor.Interactions.EditorHistoryPayload.FromBytes(System.ReadOnlySpan bytes)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryPayload.cs#L55) | Creates an immutable history payload by copying the supplied bytes.
`bytes`: The neutral bytes to retain for future Undo and Redo transitions. | A new independently owned payload. | — | | [`public byte[] Inno.Editor.Interactions.EditorHistoryPayload.ReadBytes()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryPayload.cs#L66) | Reads the complete immutable payload into a newly allocated byte array. | A copy of the payload bytes. | `System.ObjectDisposedException`: Thrown after the payload has been disposed. | | [`public void Inno.Editor.Interactions.EditorHistoryPayload.Dispose()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryPayload.cs#L90) | Releases the resident or temporary disk storage owned by this payload. | — | — | | [`public readonly record struct Inno.Editor.Interactions.EditorHistoryResult : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L8) | Describes the outcome of applying, undoing, or redoing an editor history operation. | — | — | @@ -1256,13 +1257,13 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`public bool Inno.Editor.Interactions.EditorHistoryResult.statePreserved { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L32) | Gets whether a failed transition restored the domain state that existed before the attempt. | — | — | | [`public string Inno.Editor.Interactions.EditorHistoryResult.message { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L37) | Gets the diagnostic message associated with a failed transition, or an empty string after success. | — | — | | [`public static Inno.Editor.Interactions.EditorHistoryResult Inno.Editor.Interactions.EditorHistoryResult.Success()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L45) | Creates a successful history result. | A result representing a completed transition. | — | -| [`public static Inno.Editor.Interactions.EditorHistoryResult Inno.Editor.Interactions.EditorHistoryResult.Failure(string message)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L59) | Creates a failed history result without changing the owning history stack.
`message`: The non-empty diagnostic explaining why the transition could not complete. | A result representing a rejected or failed transition. | `System.ArgumentException`: Thrown when is empty. | +| [`public static Inno.Editor.Interactions.EditorHistoryResult Inno.Editor.Interactions.EditorHistoryResult.Failure(string message)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L59) | Creates a failed history result without changing the owning history stack.
`message`: The non-empty diagnostic explaining why the transition could not complete. | A result representing a rejected or failed transition. | `System.ArgumentException`: Thrown when message is empty. | | [`public override string Inno.Editor.Interactions.EditorHistoryResult.ToString()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L8) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | -| [`public static bool Inno.Editor.Interactions.EditorHistoryResult.operator !=(Inno.Editor.Interactions.EditorHistoryResult left, Inno.Editor.Interactions.EditorHistoryResult right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L8) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.Interactions.EditorHistoryResult.operator ==(Inno.Editor.Interactions.EditorHistoryResult left, Inno.Editor.Interactions.EditorHistoryResult right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L8) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.Interactions.EditorHistoryResult.operator !=(Inno.Editor.Interactions.EditorHistoryResult left, Inno.Editor.Interactions.EditorHistoryResult right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L8) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Interactions.EditorHistoryResult.operator ==(Inno.Editor.Interactions.EditorHistoryResult left, Inno.Editor.Interactions.EditorHistoryResult right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L8) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.Interactions.EditorHistoryResult.GetHashCode()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L8) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.Interactions.EditorHistoryResult.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L8) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.Interactions.EditorHistoryResult.Equals(Inno.Editor.Interactions.EditorHistoryResult other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L8) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | +| [`public override bool Inno.Editor.Interactions.EditorHistoryResult.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L8) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Interactions.EditorHistoryResult.Equals(Inno.Editor.Interactions.EditorHistoryResult other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryResult.cs#L8) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | | [`public sealed class Inno.Editor.Interactions.EditorHistoryTransaction : System.IDisposable`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryTransaction.cs#L8) | Collects several history operations into one atomic undo and redo entry. | — | — | | [`public string Inno.Editor.Interactions.EditorHistoryTransaction.name { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryTransaction.cs#L26) | Gets the user-facing name assigned to the transaction. | — | — | | [`public void Inno.Editor.Interactions.EditorHistoryTransaction.Commit()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/EditorHistoryTransaction.cs#L36) | Commits all recorded child operations as one atomic history entry. | — | `System.InvalidOperationException`: Thrown when the transaction is no longer active. | @@ -1272,32 +1273,32 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`bool Inno.Editor.Interactions.IEditorHistory.canUndo { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L11) | Gets whether an Undo transition is currently available. | — | — | | [`bool Inno.Editor.Interactions.IEditorHistory.canRedo { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L16) | Gets whether a Redo transition is currently available. | — | — | | [`bool Inno.Editor.Interactions.IEditorHistory.isFaulted { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L21) | Gets whether a failed compensation left the domain state indeterminate. | — | — | -| [`string? Inno.Editor.Interactions.IEditorHistory.undoName { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L26) | Gets the next Undo operation name, or . | — | — | -| [`string? Inno.Editor.Interactions.IEditorHistory.redoName { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L31) | Gets the next Redo operation name, or . | — | — | -| [`string? Inno.Editor.Interactions.IEditorHistory.undoUnavailableReason { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L36) | Gets why the next Undo entry is unavailable, or . | — | — | -| [`string? Inno.Editor.Interactions.IEditorHistory.redoUnavailableReason { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L41) | Gets why the next Redo entry is unavailable, or . | — | — | -| [`string? Inno.Editor.Interactions.IEditorHistory.faultReason { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L46) | Gets the diagnostic that faulted this history, or . | — | — | +| [`string? Inno.Editor.Interactions.IEditorHistory.undoName { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L26) | Gets the next Undo operation name, or null. | — | — | +| [`string? Inno.Editor.Interactions.IEditorHistory.redoName { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L31) | Gets the next Redo operation name, or null. | — | — | +| [`string? Inno.Editor.Interactions.IEditorHistory.undoUnavailableReason { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L36) | Gets why the next Undo entry is unavailable, or null. | — | — | +| [`string? Inno.Editor.Interactions.IEditorHistory.redoUnavailableReason { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L41) | Gets why the next Redo entry is unavailable, or null. | — | — | +| [`string? Inno.Editor.Interactions.IEditorHistory.faultReason { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L46) | Gets the diagnostic that faulted this history, or null. | — | — | | [`long Inno.Editor.Interactions.IEditorHistory.residentBytes { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L51) | Gets the resident payload bytes retained by committed entries. | — | — | | [`long Inno.Editor.Interactions.IEditorHistory.diskBytes { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L56) | Gets the temporary disk payload bytes retained by committed entries. | — | — | -| [`Inno.Editor.Interactions.EditorHistoryTransaction Inno.Editor.Interactions.IEditorHistory.BeginTransaction(string name)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L67) | Begins an atomic group of neutral history operations.
`name`: The user-facing grouped operation name. | A transaction that must be committed or rolled back. | — | -| [`Inno.Editor.Interactions.EditorHistoryResult Inno.Editor.Interactions.IEditorHistory.Execute(string name, Inno.Editor.Interactions.EditorHistoryChange change)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L81) | Applies and records a neutral change through its current-generation handler.
`name`: The user-facing operation name.
`change`: The independently owned neutral change. | The result of applying the change in the Redo direction. | — | -| [`void Inno.Editor.Interactions.IEditorHistory.RecordApplied(string name, Inno.Editor.Interactions.EditorHistoryChange change)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L95) | Records a neutral change whose domain mutation is already applied.
`name`: The user-facing operation name.
`change`: The independently owned neutral change. | — | — | +| [`Inno.Editor.Interactions.EditorHistoryTransaction Inno.Editor.Interactions.IEditorHistory.BeginTransaction(string name)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L67) | Begins an atomic group of neutral history operations.
`name`: The user-facing grouped operation name. | A transaction that must be committed or rolled back. | — | +| [`Inno.Editor.Interactions.EditorHistoryResult Inno.Editor.Interactions.IEditorHistory.Execute(string name, Inno.Editor.Interactions.EditorHistoryChange change)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L81) | Applies and records a neutral change through its current-generation handler.
`name`: The user-facing operation name.
`change`: The independently owned neutral change. | The result of applying the change in the Redo direction. | — | +| [`void Inno.Editor.Interactions.IEditorHistory.RecordApplied(string name, Inno.Editor.Interactions.EditorHistoryChange change)`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L95) | Records a neutral change whose domain mutation is already applied.
`name`: The user-facing operation name.
`change`: The independently owned neutral change. | — | — | | [`Inno.Editor.Interactions.EditorHistoryResult Inno.Editor.Interactions.IEditorHistory.Undo()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L106) | Attempts to restore the state preceding the newest committed operation. | The transition result. A state-preserving failure remains available for retry. | — | | [`Inno.Editor.Interactions.EditorHistoryResult Inno.Editor.Interactions.IEditorHistory.Redo()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistory.cs#L114) | Attempts to reapply the newest reverted operation. | The transition result. A state-preserving failure remains available for retry. | — | | [`public interface Inno.Editor.Interactions.IEditorHistoryIsolation`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistoryIsolation.cs#L8) | Creates temporary history branches for transient editor workflows without exposing history internals. | — | — | | [`System.IDisposable Inno.Editor.Interactions.IEditorHistoryIsolation.BeginHistoryIsolation()`](../../src/composition/editor/framework/Inno.Editor.Interactions/History/IEditorHistoryIsolation.cs#L19) | Starts an independently disposable history branch while retaining the current editing branch. | A lease that releases the temporary branch and restores the retained branch when disposed. | `System.InvalidOperationException`: Thrown while another history transition, transaction, or isolated branch is active. | | [`public sealed class Inno.Editor.Interactions.EditorMenuAttribute : System.Attribute`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuAttribute.cs#L9) | Places an editor action at an arbitrary path on a menu surface. | — | — | -| [`public Inno.Editor.Interactions.EditorMenuAttribute.EditorMenuAttribute(string area, string path, int order = 0, bool separatorBefore = false)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuAttribute.cs#L29) | Creates a static placement for the annotated action on an exact menu surface.
`area`: The exact interaction area whose menu receives the action.
`path`: The slash-delimited path used to create parent menus and the leaf label.
`order`: The stable ordering value among sibling placements.
`separatorBefore`: Whether a visual separator should precede the leaf placement. | — | `System.ArgumentException`: Thrown when or is empty. | +| [`public Inno.Editor.Interactions.EditorMenuAttribute.EditorMenuAttribute(string area, string path, int order = 0, bool separatorBefore = false)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuAttribute.cs#L29) | Creates a static placement for the annotated action on an exact menu surface.
`area`: The exact interaction area whose menu receives the action.
`path`: The slash-delimited path used to create parent menus and the leaf label.
`order`: The stable ordering value among sibling placements.
`separatorBefore`: Whether a visual separator should precede the leaf placement. | — | `System.ArgumentException`: Thrown when area or path is empty. | | [`public string Inno.Editor.Interactions.EditorMenuAttribute.area { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuAttribute.cs#L48) | Gets the menu area. | — | — | | [`public string Inno.Editor.Interactions.EditorMenuAttribute.path { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuAttribute.cs#L53) | Gets the slash-delimited menu path. | — | — | | [`public int Inno.Editor.Interactions.EditorMenuAttribute.order { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuAttribute.cs#L58) | Gets the stable menu ordering value. | — | — | | [`public bool Inno.Editor.Interactions.EditorMenuAttribute.separatorBefore { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuAttribute.cs#L63) | Gets whether a separator is rendered before the item. | — | — | | [`public sealed class Inno.Editor.Interactions.EditorMenuBuilder`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuBuilder.cs#L9) | Collects dynamic menu item placements. | — | — | -| [`public void Inno.Editor.Interactions.EditorMenuBuilder.AddGroup(string path, int order = 0, bool separatorBefore = false)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuBuilder.cs#L26) | Declares presentation for an intermediate menu group without inventing a no-op action.
`path`: The slash-delimited path of the group.
`order`: The stable ordering value among sibling groups and items.
`separatorBefore`: Whether a separator precedes this group at its own level. | — | — | -| [`public void Inno.Editor.Interactions.EditorMenuBuilder.Add(string path, string actionId, int order = 0, bool separatorBefore = false, object? argument = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuBuilder.cs#L57) | Adds a dynamic action placement to the menu currently being constructed.
`path`: The slash-delimited path used to create parent menus and the leaf label.
`actionId`: The stable action identifier invoked by the leaf.
`order`: The stable ordering value among sibling placements.
`separatorBefore`: Whether a visual separator should precede the leaf placement.
`argument`: An optional argument captured for this menu generation. | — | `System.ArgumentException`: Thrown when or is empty. | -| [`public Inno.Editor.Interactions.EditorMenuBuilder.EditorMenuBuilder()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuBuilder.cs#L9) | Inherited or compiler-provided contract. | — | — | +| [`public void Inno.Editor.Interactions.EditorMenuBuilder.AddGroup(string path, int order = 0, bool separatorBefore = false)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuBuilder.cs#L26) | Declares presentation for an intermediate menu group without inventing a no-op action.
`path`: The slash-delimited path of the group.
`order`: The stable ordering value among sibling groups and items.
`separatorBefore`: Whether a separator precedes this group at its own level. | — | — | +| [`public void Inno.Editor.Interactions.EditorMenuBuilder.Add(string path, string actionId, int order = 0, bool separatorBefore = false, object? argument = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuBuilder.cs#L57) | Adds a dynamic action placement to the menu currently being constructed.
`path`: The slash-delimited path used to create parent menus and the leaf label.
`actionId`: The stable action identifier invoked by the leaf.
`order`: The stable ordering value among sibling placements.
`separatorBefore`: Whether a visual separator should precede the leaf placement.
`argument`: An optional argument captured for this menu generation. | — | `System.ArgumentException`: Thrown when path or actionId is empty. | +| [`public Inno.Editor.Interactions.EditorMenuBuilder.EditorMenuBuilder()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuBuilder.cs#L9) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public sealed class Inno.Editor.Interactions.EditorMenuContext`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuContext.cs#L10) | Provides contextual state while constructing an editor menu. | — | — | -| [`public Inno.Editor.Interactions.EditorMenuContext.EditorMenuContext(Inno.Editor.Core.EditorContext editor, Inno.Editor.Interactions.EditorInteractions interactions, string area, object? target = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuContext.cs#L33) | Creates a contextual menu request.
`editor`: The shared passive editor context.
`interactions`: The active interaction entry point.
`area`: The exact menu area being requested.
`target`: The optional object the menu operates on. | — | `System.ArgumentNullException`: Thrown when or is .
`System.ArgumentException`: Thrown when is empty. | +| [`public Inno.Editor.Interactions.EditorMenuContext.EditorMenuContext(Inno.Editor.Core.EditorContext editor, Inno.Editor.Interactions.EditorInteractions interactions, string area, object? target = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuContext.cs#L33) | Creates a contextual menu request.
`editor`: The shared passive editor context.
`interactions`: The active interaction entry point.
`area`: The exact menu area being requested.
`target`: The optional object the menu operates on. | — | `System.ArgumentNullException`: Thrown when editor or interactions is null.
`System.ArgumentException`: Thrown when area is empty. | | [`public Inno.Editor.Core.EditorContext Inno.Editor.Interactions.EditorMenuContext.editor { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuContext.cs#L49) | Gets the shared passive editor context. | — | — | | [`public Inno.Editor.Interactions.EditorInteractions Inno.Editor.Interactions.EditorMenuContext.interactions { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuContext.cs#L54) | Gets the active interaction entry point. | — | — | | [`public string Inno.Editor.Interactions.EditorMenuContext.area { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuContext.cs#L59) | Gets the requested menu area. | — | — | @@ -1311,13 +1312,13 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`public System.Collections.Generic.IReadOnlyList Inno.Editor.Interactions.EditorMenuItem.children { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuItem.cs#L84) | Gets child menu nodes. | — | — | | [`public object? Inno.Editor.Interactions.EditorMenuItem.argument { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuItem.cs#L90) | Gets the generation-local action argument consumed by a presentation backend. | — | — | | [`public sealed class Inno.Editor.Interactions.EditorMenuModel`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuModel.cs#L9) | Contains a complete immutable menu tree. | — | — | -| [`public Inno.Editor.Interactions.EditorMenuModel.EditorMenuModel(System.Collections.Generic.IReadOnlyList? items)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuModel.cs#L17) | Creates a complete immutable menu tree from resolved root nodes.
`items`: The root nodes in stable display order, or for an empty menu. | — | — | +| [`public Inno.Editor.Interactions.EditorMenuModel.EditorMenuModel(System.Collections.Generic.IReadOnlyList? items)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuModel.cs#L17) | Creates a complete immutable menu tree from resolved root nodes.
`items`: The root nodes in stable display order, or null for an empty menu. | — | — | | [`public System.Collections.Generic.IReadOnlyList Inno.Editor.Interactions.EditorMenuModel.items { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuModel.cs#L25) | Gets root menu nodes in display order. | — | — | | [`public abstract class Inno.Editor.Interactions.EditorMenuSource`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuSource.cs#L8) | Contributes dynamic entries to one or more editor menu surfaces. | — | — | -| [`public abstract void Inno.Editor.Interactions.EditorMenuSource.Build(Inno.Editor.Interactions.EditorMenuContext context, Inno.Editor.Interactions.EditorMenuBuilder builder)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuSource.cs#L19) | Adds context-dependent placements for the supplied menu request.
`context`: The requested menu surface, target, and shared editor context.
`builder`: The collector that receives dynamic action placements. | — | — | -| [`protected Inno.Editor.Interactions.EditorMenuSource.EditorMenuSource()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuSource.cs#L8) | Inherited or compiler-provided contract. | — | — | +| [`public abstract void Inno.Editor.Interactions.EditorMenuSource.Build(Inno.Editor.Interactions.EditorMenuContext context, Inno.Editor.Interactions.EditorMenuBuilder builder)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuSource.cs#L19) | Adds context-dependent placements for the supplied menu request.
`context`: The requested menu surface, target, and shared editor context.
`builder`: The collector that receives dynamic action placements. | — | — | +| [`protected Inno.Editor.Interactions.EditorMenuSource.EditorMenuSource()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuSource.cs#L8) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public sealed class Inno.Editor.Interactions.EditorMenuSourceAttribute : System.Attribute`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuSourceAttribute.cs#L9) | Registers a dynamic editor menu source. | — | — | -| [`public Inno.Editor.Interactions.EditorMenuSourceAttribute.EditorMenuSourceAttribute(string area, int priority = 0)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuSourceAttribute.cs#L23) | Creates a dynamic menu-source registration for an exact interaction surface.
`area`: The exact menu area that receives placements from the source.
`priority`: The ordering priority used when multiple dynamic sources contribute to the surface. | — | `System.ArgumentException`: Thrown when is empty. | +| [`public Inno.Editor.Interactions.EditorMenuSourceAttribute.EditorMenuSourceAttribute(string area, int priority = 0)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuSourceAttribute.cs#L23) | Creates a dynamic menu-source registration for an exact interaction surface.
`area`: The exact menu area that receives placements from the source.
`priority`: The ordering priority used when multiple dynamic sources contribute to the surface. | — | `System.ArgumentException`: Thrown when area is empty. | | [`public string Inno.Editor.Interactions.EditorMenuSourceAttribute.area { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuSourceAttribute.cs#L36) | Gets the contributed menu area. | — | — | | [`public int Inno.Editor.Interactions.EditorMenuSourceAttribute.priority { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Menus/EditorMenuSourceAttribute.cs#L41) | Gets the provider ordering priority. | — | — | | [`public readonly struct Inno.Editor.Interactions.EditorInteraction`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L14) | Provides a fluent handle that borrows an optional target for a synchronous interaction request. | — | — | @@ -1325,34 +1326,34 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`public object? Inno.Editor.Interactions.EditorInteraction.target { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L35) | Gets the borrowed target without extending its validity or resolving a replacement generation. | — | — | | [`public bool Inno.Editor.Interactions.EditorInteraction.isSelected { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L39) | Gets whether this handle's target is the current editor selection. | — | — | | [`public void Inno.Editor.Interactions.EditorInteraction.Focus()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L44) | Marks this area and target as the active keyboard context. | — | — | -| [`public bool Inno.Editor.Interactions.EditorInteraction.Select()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L51) | Selects this target, or clears selection when the target is . | when the built-in selection action executed; otherwise, . | — | -| [`public Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorInteraction.Query(string action, object? argument = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L67) | Queries an action for this area and target.
`action`: The stable action name.
`argument`: An optional action argument. | The current action state. | `System.ArgumentException`: Thrown when is empty. | -| [`public bool Inno.Editor.Interactions.EditorInteraction.Execute(string action, object? argument = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L86) | Executes an action for this area and target.
`action`: The stable action name.
`argument`: An optional action argument. | when a visible and enabled action executed; otherwise, . | `System.ArgumentException`: Thrown when is empty. | -| [`public void Inno.Editor.Interactions.EditorInteraction.Enqueue(string action, object? argument = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L102) | Queues an action until the current UI traversal completes.
`action`: The stable action name.
`argument`: An optional action argument. | — | `System.ArgumentException`: Thrown when is empty. | -| [`public bool Inno.Editor.Interactions.EditorInteraction.Present(string action, object? argument = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L121) | Presents an active action in place of this target's normal content.
`action`: The stable action name.
`argument`: Optional presentation data supplied by the current view. | when the action presented content; otherwise, . | `System.ArgumentException`: Thrown when is empty. | -| [`public bool Inno.Editor.Interactions.EditorInteraction.IsActive(string action)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L137) | Gets whether an action owns an active multi-frame operation for this target.
`action`: The stable action name. | when the action is active for this exact target; otherwise, . | `System.ArgumentException`: Thrown when is empty. | +| [`public bool Inno.Editor.Interactions.EditorInteraction.Select()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L51) | Selects this target, or clears selection when the target is null. | true when the built-in selection action executed; otherwise, false. | — | +| [`public Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorInteraction.Query(string action, object? argument = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L67) | Queries an action for this area and target.
`action`: The stable action name.
`argument`: An optional action argument. | The current action state. | `System.ArgumentException`: Thrown when action is empty. | +| [`public bool Inno.Editor.Interactions.EditorInteraction.Execute(string action, object? argument = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L86) | Executes an action for this area and target.
`action`: The stable action name.
`argument`: An optional action argument. | true when a visible and enabled action executed; otherwise, false. | `System.ArgumentException`: Thrown when action is empty. | +| [`public void Inno.Editor.Interactions.EditorInteraction.Enqueue(string action, object? argument = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L102) | Queues an action until the current UI traversal completes.
`action`: The stable action name.
`argument`: An optional action argument. | — | `System.ArgumentException`: Thrown when action is empty. | +| [`public bool Inno.Editor.Interactions.EditorInteraction.Present(string action, object? argument = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L121) | Presents an active action in place of this target's normal content.
`action`: The stable action name.
`argument`: Optional presentation data supplied by the current view. | true when the action presented content; otherwise, false. | `System.ArgumentException`: Thrown when action is empty. | +| [`public bool Inno.Editor.Interactions.EditorInteraction.IsActive(string action)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L137) | Gets whether an action owns an active multi-frame operation for this target.
`action`: The stable action name. | true when the action is active for this exact target; otherwise, false. | `System.ArgumentException`: Thrown when action is empty. | | [`public Inno.Editor.Interactions.EditorMenuModel Inno.Editor.Interactions.EditorInteraction.BuildMenu()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L144) | Builds the complete contextual menu for this area and target. | The immutable resolved menu model. | — | | [`public Inno.Editor.Interactions.EditorMenuModel Inno.Editor.Interactions.EditorInteraction.BuildCommands()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L151) | Builds searchable commands from this area's menus and applicable unplaced Actions. | Current command states and neutral placement arguments; execution revalidates their targets. | — | | [`public Inno.Editor.Interactions.EditorToolbarModel Inno.Editor.Interactions.EditorInteraction.BuildToolbar()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L158) | Builds the complete compact toolbar for this area and target. | The immutable resolved toolbar model. | — | -| [`public bool Inno.Editor.Interactions.EditorInteraction.TryGetShortcut(string action, out Inno.Editor.Interactions.HotKeyGesture gesture)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L174) | Resolves the shortcut displayed for an action in this area.
`action`: The stable action name.
`gesture`: The resolved gesture when successful. | when a compatible shortcut exists; otherwise, . | `System.ArgumentException`: Thrown when is empty. | -| [`public bool Inno.Editor.Interactions.EditorInteraction.TryGetActiveDragIdentity(out Inno.Core.Identity.RuntimeIdentity identity)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L187) | Gets the currently active drag identity, if its source remains registered.
`identity`: The active domain-qualified runtime identity when available. | when a live drag source exists; otherwise, . | — | -| [`public Inno.Core.Identity.RuntimeIdentity Inno.Editor.Interactions.EditorInteraction.BeginDrag(Inno.Editor.Interactions.EditorDragData data)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L197) | Begins a managed drag originating from this area.
`data`: The managed source data. | The source object's domain-qualified transient identity. | — | -| [`public Inno.Editor.Interactions.EditorDropStatus Inno.Editor.Interactions.EditorInteraction.QueryDrop(Inno.Core.Identity.RuntimeIdentity identity, Inno.Editor.Interactions.EditorDropPlacement placement = Inno.Editor.Interactions.EditorDropPlacement.None)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L210) | Queries this handle as a drop target.
`identity`: The active domain-qualified runtime identity.
`placement`: The requested placement relative to the target. | The drop compatibility and visual state. | — | -| [`public Inno.Editor.Interactions.EditorDropResult Inno.Editor.Interactions.EditorInteraction.Drop(Inno.Core.Identity.RuntimeIdentity identity, Inno.Editor.Interactions.EditorDropPlacement placement = Inno.Editor.Interactions.EditorDropPlacement.None)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L226) | Delivers a managed drop to this target.
`identity`: The active domain-qualified runtime identity.
`placement`: The requested placement relative to the target. | The completed drop result. | — | +| [`public bool Inno.Editor.Interactions.EditorInteraction.TryGetShortcut(string action, out Inno.Editor.Interactions.HotKeyGesture gesture)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L174) | Resolves the shortcut displayed for an action in this area.
`action`: The stable action name.
`gesture`: The resolved gesture when successful. | true when a compatible shortcut exists; otherwise, false. | `System.ArgumentException`: Thrown when action is empty. | +| [`public bool Inno.Editor.Interactions.EditorInteraction.TryGetActiveDragIdentity(out Inno.Core.Identity.RuntimeIdentity identity)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L187) | Gets the currently active drag identity, if its source remains registered.
`identity`: The active domain-qualified runtime identity when available. | true when a live drag source exists; otherwise, false. | — | +| [`public Inno.Core.Identity.RuntimeIdentity Inno.Editor.Interactions.EditorInteraction.BeginDrag(Inno.Editor.Interactions.EditorDragData data)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L197) | Begins a managed drag originating from this area.
`data`: The managed source data. | The source object's domain-qualified transient identity. | — | +| [`public Inno.Editor.Interactions.EditorDropStatus Inno.Editor.Interactions.EditorInteraction.QueryDrop(Inno.Core.Identity.RuntimeIdentity identity, Inno.Editor.Interactions.EditorDropPlacement placement = Inno.Editor.Interactions.EditorDropPlacement.None)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L210) | Queries this handle as a drop target.
`identity`: The active domain-qualified runtime identity.
`placement`: The requested placement relative to the target. | The drop compatibility and visual state. | — | +| [`public Inno.Editor.Interactions.EditorDropResult Inno.Editor.Interactions.EditorInteraction.Drop(Inno.Core.Identity.RuntimeIdentity identity, Inno.Editor.Interactions.EditorDropPlacement placement = Inno.Editor.Interactions.EditorDropPlacement.None)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteraction.cs#L226) | Delivers a managed drop to this target.
`identity`: The active domain-qualified runtime identity.
`placement`: The requested placement relative to the target. | The completed drop result. | — | | [`public sealed class Inno.Editor.Interactions.EditorInteractionRuntime : Inno.Editor.Core.EditorRuntime`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L17) | Hosts attribute-discovered editor extensions without depending on a presentation backend. | — | — | -| [`public Inno.Editor.Interactions.EditorInteractionRuntime.EditorInteractionRuntime(string projectDirectory, Inno.Extensibility.Types.TypeCatalog types, Inno.Core.Logging.LogRouter logs, Inno.Editor.Core.EditorKeyboardPolicy keyboard)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L46) | Creates an interaction runtime for one project.
`projectDirectory`: The project root containing Assets and Library.
`types`: The type catalog that owns editor extension generations.
`logs`: The host-owned logging router used by editor infrastructure.
`keyboard`: The explicit immutable product keyboard conventions. | — | — | -| [`public Inno.Editor.Interactions.EditorInteractionRuntime.EditorInteractionRuntime(Inno.Editor.Core.EditorContext context, Inno.Extensibility.Types.TypeCatalog types, Inno.Core.Logging.LogRouter logs)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L71) | Creates an interaction runtime for an existing passive editor context.
`context`: The passive editor context shared with the presentation backend.
`types`: The type catalog that owns editor extension generations.
`logs`: The host-owned logging router used by editor infrastructure. | — | `System.ArgumentNullException`: Thrown when or is . | -| [`public Inno.Editor.Interactions.EditorInteractionRuntime.EditorInteractionRuntime(Inno.Editor.Core.EditorContext context, Inno.Extensibility.Types.TypeCatalog types, Inno.Core.Logging.LogRouter logs, System.Collections.Generic.IEnumerable hostServices)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L98) | Creates an interaction runtime with stable host-owned extension services.
`context`: The passive editor context shared with the presentation backend.
`hostServices`: Stable host-owned services that editor extension constructors may request by assignable contract.
`logs`: The host-owned logging router used by editor infrastructure.
`types`: The type catalog that owns editor extension generations. | — | `System.ArgumentNullException`: Thrown when or is . | +| [`public Inno.Editor.Interactions.EditorInteractionRuntime.EditorInteractionRuntime(string projectDirectory, Inno.Extensibility.Types.TypeCatalog types, Inno.Core.Logging.LogRouter logs, Inno.Editor.Core.EditorKeyboardPolicy keyboard)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L46) | Creates an interaction runtime for one project.
`projectDirectory`: The project root containing Assets and Library.
`types`: The type catalog that owns editor extension generations.
`logs`: The host-owned logging router used by editor infrastructure.
`keyboard`: The explicit immutable product keyboard conventions. | — | — | +| [`public Inno.Editor.Interactions.EditorInteractionRuntime.EditorInteractionRuntime(Inno.Editor.Core.EditorContext context, Inno.Extensibility.Types.TypeCatalog types, Inno.Core.Logging.LogRouter logs)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L71) | Creates an interaction runtime for an existing passive editor context.
`context`: The passive editor context shared with the presentation backend.
`types`: The type catalog that owns editor extension generations.
`logs`: The host-owned logging router used by editor infrastructure. | — | `System.ArgumentNullException`: Thrown when context or logs is null. | +| [`public Inno.Editor.Interactions.EditorInteractionRuntime.EditorInteractionRuntime(Inno.Editor.Core.EditorContext context, Inno.Extensibility.Types.TypeCatalog types, Inno.Core.Logging.LogRouter logs, System.Collections.Generic.IEnumerable hostServices)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L98) | Creates an interaction runtime with stable host-owned extension services.
`context`: The passive editor context shared with the presentation backend.
`hostServices`: Stable host-owned services that editor extension constructors may request by assignable contract.
`logs`: The host-owned logging router used by editor infrastructure.
`types`: The type catalog that owns editor extension generations. | — | `System.ArgumentNullException`: Thrown when context or hostServices is null. | | [`public Inno.Editor.Interactions.EditorInteractions Inno.Editor.Interactions.EditorInteractionRuntime.interactions { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L128) | Gets the active presentation-independent interaction entry point. | — | — | | [`public System.Collections.Generic.IReadOnlyList Inno.Editor.Interactions.EditorInteractionRuntime.panels { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L133) | Gets active dockable panel extensions in deterministic order. | — | — | | [`public System.Collections.Generic.IReadOnlyList Inno.Editor.Interactions.EditorInteractionRuntime.modals { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L145) | Gets active modal extensions in deterministic order. | — | — | | [`public int Inno.Editor.Interactions.EditorInteractionRuntime.panelCount { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L157) | Gets the number of active dockable panels. | — | — | | [`public override void Inno.Editor.Interactions.EditorInteractionRuntime.Start()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L162) | Starts value processing after validating the current state. | — | — | -| [`public override void Inno.Editor.Interactions.EditorInteractionRuntime.Update(Inno.Editor.Core.EditorFrame frame)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L179) | Recomputes owned state from the current validated inputs.
`frame`: The frame consumed by update; ownership remains with the caller unless explicitly stated otherwise. | — | — | +| [`public override void Inno.Editor.Interactions.EditorInteractionRuntime.Update(Inno.Editor.Core.EditorFrame frame)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L179) | Recomputes owned state from the current validated inputs.
`frame`: The frame consumed by update; ownership remains with the caller unless explicitly stated otherwise. | — | — | | [`public void Inno.Editor.Interactions.EditorInteractionRuntime.Flush()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L194) | Flushes actions queued during the current presentation traversal. | — | — | | [`public void Inno.Editor.Interactions.EditorInteractionRuntime.SaveState()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L203) | Captures every stateful active module and panel and atomically flushes changed project state to disk. | — | `System.ObjectDisposedException`: Thrown after this runtime has been disposed. | | [`public void Inno.Editor.Interactions.EditorInteractionRuntime.PrepareShutdown()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L220) | Freezes automatic extension-state persistence and writes the final state before modules begin shutting down. | — | `System.ObjectDisposedException`: Thrown after this runtime has been disposed. | -| [`public void Inno.Editor.Interactions.EditorInteractionRuntime.HandleKeyPressed(Inno.Core.Events.KeyPressedEvent keyEvent)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L232) | Dispatches an unhandled keyboard event through contextual shortcuts.
`keyEvent`: The keyboard event received from the application event stream. | — | — | +| [`public void Inno.Editor.Interactions.EditorInteractionRuntime.HandleKeyPressed(Inno.Core.Events.KeyPressedEvent keyEvent)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L232) | Dispatches an unhandled keyboard event through contextual shortcuts.
`keyEvent`: The keyboard event received from the application event stream. | — | — | | [`public override void Inno.Editor.Interactions.EditorInteractionRuntime.Dispose()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractionRuntime.cs#L248) | Releases the resources owned by this implementation. | — | `System.AggregateException`: Thrown after all shutdown stages have been attempted when one or more stages failed.
`Inno.Core.Execution.RetirementPendingException`: A stage still owns live work. This runtime retains all remaining stages and rejects new updates. | | [`public sealed class Inno.Editor.Interactions.EditorInteractions : Inno.Editor.Interactions.IEditorSelectionCoordinator, Inno.Editor.Interactions.IEditorHistoryIsolation`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L15) | Provides the single presentation-independent entry point for editor actions, menus, selection, focus, and drag-and-drop. | — | — | | [`public Inno.Core.Events.EventDispatcher Inno.Editor.Interactions.EditorInteractions.events { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L57) | Gets synchronous Editor lifecycle notifications implemented by the Core event dispatcher. | — | — | @@ -1360,72 +1361,73 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`public Inno.Editor.Core.EditorKeyboardPolicy Inno.Editor.Interactions.EditorInteractions.keyboard { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L68) | Gets the immutable product keyboard policy used by commands and selection controls. | — | — | | [`public Inno.Editor.Interactions.IEditorHistory Inno.Editor.Interactions.EditorInteractions.history { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L74) | Gets the transactional Undo and Redo history owned by this editor runtime. | — | — | | [`public Inno.Editor.Interactions.IEditorDocumentService Inno.Editor.Interactions.EditorInteractions.documents { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L78) | Gets the headless reload-safe document lifetime used by dedicated asset editors and Inspectors. | — | — | -| [`public bool Inno.Editor.Interactions.EditorInteractions.TryGetModule(out TModule? module) where TModule : Inno.Editor.Core.EditorModule`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L95) | Resolves an active feature module for immediate use in the current Editor callback.
`module`: The started, non-quarantined module, or null when unavailable.
`TModule`: The feature module contract to resolve. | True when the active generation supplies the requested module. | — | +| [`public bool Inno.Editor.Interactions.EditorInteractions.TryGetModule(out TModule? module) where TModule : Inno.Editor.Core.EditorModule`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L95) | Resolves an active feature module for immediate use in the current Editor callback.
`TModule`: The feature module contract to resolve.
`module`: The started, non-quarantined module, or null when unavailable. | True when the active generation supplies the requested module. | — | | [`public System.IDisposable Inno.Editor.Interactions.EditorInteractions.BeginHistoryIsolation()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L118) | Starts an isolated temporary Undo and Redo branch while retaining the current editing branch. | A scope that restores the retained history branch when disposed. | `System.InvalidOperationException`: Thrown during an Undo, Redo, transaction, or another isolated branch. | | [`public string Inno.Editor.Interactions.EditorInteractions.focusedArea { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L123) | Gets the area that most recently received keyboard focus. | — | — | | [`public System.Collections.Generic.IReadOnlyList Inno.Editor.Interactions.EditorInteractions.GetPanelDeclarations()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L131) | Gets immutable discovery metadata for the active, available panels. | Current panel declarations; the snapshot contains no panel or extension instances. | — | -| [`public bool Inno.Editor.Interactions.EditorInteractions.TryGetPanelState(string panelId, out bool isOpen)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L144) | Reads whether one available panel is currently open.
`panelId`: The stable panel identity.
`isOpen`: Receives the open state, or false when the panel is unavailable. | True when the current generation contains the requested available panel. | — | +| [`public bool Inno.Editor.Interactions.EditorInteractions.TryGetPanelState(string panelId, out bool isOpen)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L144) | Reads whether one available panel is currently open.
`panelId`: The stable panel identity.
`isOpen`: Receives the open state, or false when the panel is unavailable. | True when the current generation contains the requested available panel. | — | | [`public object? Inno.Editor.Interactions.EditorInteractions.focusedTarget { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L156) | Gets the target associated with the focused area. | — | — | -| [`public Inno.Editor.Interactions.EditorInteraction Inno.Editor.Interactions.EditorInteractions.For(string area, object? target = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L173) | Creates a lightweight interaction handle for one area and optional target.
`area`: The stable interaction area.
`target`: The optional object represented by the area. | A lightweight interaction handle. | `System.ArgumentException`: Thrown when is empty. | -| [`public void Inno.Editor.Interactions.EditorInteractions.SetSelection(object? target)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L183) | Replaces the editor selection after closing presentations owned by other targets.
`target`: The target to select, or to clear the selection. | — | — | -| [`public void Inno.Editor.Interactions.EditorInteractions.SetSelection(System.Collections.Generic.IEnumerable targets, Inno.Core.Identity.IdentityObject? anchor)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L208) | Replaces the ordered selection; duplicates are removed and the final target becomes primary.
`targets`: Registered objects resolved for the current callback.
`anchor`: The range anchor, or null to use the first selected target. | — | `System.ArgumentNullException`: The target collection or one member is null.
`System.InvalidOperationException`: A target has no live identity registration. | -| [`public void Inno.Editor.Interactions.EditorInteractions.ToggleSelection(Inno.Core.Identity.IdentityObject target)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L226) | Adds or removes a member while preserving the existing range anchor.
`target`: A currently registered selection target. | — | `System.ArgumentNullException`: The target is null. | -| [`public void Inno.Editor.Interactions.EditorInteractions.SelectRange(System.Collections.Generic.IReadOnlyList orderedTargets, Inno.Core.Identity.IdentityObject target, bool additive = false)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L258) | Selects the inclusive visible range between the current anchor and the clicked target.
`orderedTargets`: Runtime identities in the current visible sort and filter order, resolved through Core Identity only when selected.
`target`: The clicked range endpoint, which becomes primary.
`additive`: Whether to preserve existing members outside the selected range. | — | `System.ArgumentNullException`: The visible targets or endpoint is null.
`System.ArgumentException`: The endpoint is not in the visible target order.
`System.InvalidOperationException`: A range identity is unavailable; the current selection remains unchanged. | -| [`public bool Inno.Editor.Interactions.EditorInteractions.TryGetDragSource(Inno.Core.Identity.RuntimeIdentity identity, out Inno.Core.Identity.IdentityObject? source)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L313) | Resolves the live source for an active runtime identity.
`identity`: The domain-qualified runtime identity carried by the drag protocol.
`source`: The currently registered drag source when resolution succeeds. | when the identity is active and resolves to a live source; otherwise, . | — | -| [`public bool Inno.Editor.Interactions.EditorInteractions.TryGetActiveDragIdentity(out Inno.Core.Identity.RuntimeIdentity identity)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L326) | Gets the active drag identity used to select the matching native payload domain.
`identity`: The active runtime identity when one remains valid. | when a live drag source exists; otherwise, . | — | -| [`public bool Inno.Editor.Interactions.EditorInteractions.TogglePanel(string panelId)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L339) | Toggles one panel in the currently active extension generation.
`panelId`: The stable panel identifier to resolve. | when an available panel was found and toggled. | `System.ArgumentException`: Thrown when is empty. | -| [`public System.IDisposable Inno.Editor.Interactions.EditorInteractions.RegisterIdentityDomain(Inno.Core.Identity.IdentityAllocator allocator)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L364) | Makes a temporary Core identity domain available to selection, focus and drag resolution.
`allocator`: The borrowed allocator owned by the temporary runtime session. | A routing lease; retire it after restoring Edit selection and before releasing the session. | `System.ArgumentNullException`: The allocator is null.
`System.InvalidOperationException`: The domain is already registered or the caller is not the owner thread.
`System.ObjectDisposedException`: The interaction runtime has retired its identity routing. | -| [`public bool Inno.Editor.Interactions.EditorInteractions.TryResolveIdentity(Inno.Core.Identity.RuntimeIdentity identity, out Inno.Core.Identity.IdentityObject? target)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L387) | Resolves a domain-qualified runtime identity through the Editor's complete identity-domain set.
`identity`: Runtime identity captured from a live Editor target.
`target`: Receives the current live object, or when its domain or generation is unavailable. | when the exact identity resolves in its owning domain. | — | -| [`public bool Inno.Editor.Interactions.EditorInteractions.TryResolveIdentity(Inno.Core.Identity.IdentityDomainId domainId, System.Guid persistentId, out Inno.Core.Identity.IdentityObject? target)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L411) | Resolves a persistent identity through one explicitly selected Editor identity domain.
`domainId`: Identity domain that owns the object and any replacement generation.
`persistentId`: Stable object identity to resolve inside that domain.
`target`: Receives the current live object, or when the domain or object is unavailable. | when the stable identity resolves in the requested domain. | — | -| [`public bool Inno.Editor.Interactions.EditorInteractions.OpenPanel(string panelId)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L432) | Opens and requests presentation focus for one panel in the active extension generation.
`panelId`: The stable panel identifier to resolve. | when an available panel was found. | `System.ArgumentException`: Thrown when is empty. | -| [`public bool Inno.Editor.Interactions.EditorInteractions.ClosePanel(string panelId)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L450) | Closes one panel in the active extension generation without toggling its current state.
`panelId`: The stable panel identifier to resolve. | when an available panel was found. | `System.ArgumentException`: Thrown when is empty. | +| [`public Inno.Editor.Interactions.EditorInteraction Inno.Editor.Interactions.EditorInteractions.For(string area, object? target = null)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L173) | Creates a lightweight interaction handle for one area and optional target.
`area`: The stable interaction area.
`target`: The optional object represented by the area. | A lightweight interaction handle. | `System.ArgumentException`: Thrown when area is empty. | +| [`public void Inno.Editor.Interactions.EditorInteractions.SetSelection(object? target)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L183) | Replaces the editor selection after closing presentations owned by other targets.
`target`: The target to select, or null to clear the selection. | — | — | +| [`public void Inno.Editor.Interactions.EditorInteractions.SetSelection(System.Collections.Generic.IEnumerable targets, Inno.Core.Identity.IdentityObject? anchor)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L208) | Replaces the ordered selection; duplicates are removed and the final target becomes primary.
`targets`: Registered objects resolved for the current callback.
`anchor`: The range anchor, or null to use the first selected target. | — | `System.ArgumentNullException`: The target collection or one member is null.
`System.InvalidOperationException`: A target has no live identity registration. | +| [`public void Inno.Editor.Interactions.EditorInteractions.ToggleSelection(Inno.Core.Identity.IdentityObject target)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L226) | Adds or removes a member while preserving the existing range anchor.
`target`: A currently registered selection target. | — | `System.ArgumentNullException`: The target is null. | +| [`public void Inno.Editor.Interactions.EditorInteractions.SelectRange(System.Collections.Generic.IReadOnlyList orderedTargets, Inno.Core.Identity.IdentityObject target, bool additive = false)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L258) | Selects the inclusive visible range between the current anchor and the clicked target.
`orderedTargets`: Runtime identities in the current visible sort and filter order, resolved through Core Identity only when selected.
`target`: The clicked range endpoint, which becomes primary.
`additive`: Whether to preserve existing members outside the selected range. | — | `System.ArgumentNullException`: The visible targets or endpoint is null.
`System.ArgumentException`: The endpoint is not in the visible target order.
`System.InvalidOperationException`: A range identity is unavailable; the current selection remains unchanged. | +| [`public bool Inno.Editor.Interactions.EditorInteractions.TryGetDragSource(Inno.Core.Identity.RuntimeIdentity identity, out Inno.Core.Identity.IdentityObject? source)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L313) | Resolves the live source for an active runtime identity.
`identity`: The domain-qualified runtime identity carried by the drag protocol.
`source`: The currently registered drag source when resolution succeeds. | true when the identity is active and resolves to a live source; otherwise, false. | — | +| [`public bool Inno.Editor.Interactions.EditorInteractions.TryGetActiveDragIdentity(out Inno.Core.Identity.RuntimeIdentity identity)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L326) | Gets the active drag identity used to select the matching native payload domain.
`identity`: The active runtime identity when one remains valid. | true when a live drag source exists; otherwise, false. | — | +| [`public bool Inno.Editor.Interactions.EditorInteractions.TogglePanel(string panelId)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L339) | Toggles one panel in the currently active extension generation.
`panelId`: The stable panel identifier to resolve. | true when an available panel was found and toggled. | `System.ArgumentException`: Thrown when panelId is empty. | +| [`public System.IDisposable Inno.Editor.Interactions.EditorInteractions.RegisterIdentityDomain(Inno.Core.Identity.IdentityAllocator allocator)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L364) | Makes a temporary Core identity domain available to selection, focus and drag resolution.
`allocator`: The borrowed allocator owned by the temporary runtime session. | A routing lease; retire it after restoring Edit selection and before releasing the session. | `System.ArgumentNullException`: The allocator is null.
`System.InvalidOperationException`: The domain is already registered or the caller is not the owner thread.
`System.ObjectDisposedException`: The interaction runtime has retired its identity routing. | +| [`public bool Inno.Editor.Interactions.EditorInteractions.TryResolveIdentity(Inno.Core.Identity.RuntimeIdentity identity, out Inno.Core.Identity.IdentityObject? target)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L387) | Resolves a domain-qualified runtime identity through the Editor's complete identity-domain set.
`identity`: Runtime identity captured from a live Editor target.
`target`: Receives the current live object, or null when its domain or generation is unavailable. | true when the exact identity resolves in its owning domain. | — | +| [`public bool Inno.Editor.Interactions.EditorInteractions.TryResolveIdentity(Inno.Core.Identity.IdentityDomainId domainId, System.Guid persistentId, out Inno.Core.Identity.IdentityObject? target)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L411) | Resolves a persistent identity through one explicitly selected Editor identity domain.
`domainId`: Identity domain that owns the object and any replacement generation.
`persistentId`: Stable object identity to resolve inside that domain.
`target`: Receives the current live object, or null when the domain or object is unavailable. | true when the stable identity resolves in the requested domain. | — | +| [`public bool Inno.Editor.Interactions.EditorInteractions.OpenPanel(string panelId)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L432) | Opens and requests presentation focus for one panel in the active extension generation.
`panelId`: The stable panel identifier to resolve. | true when an available panel was found. | `System.ArgumentException`: Thrown when panelId is empty. | +| [`public bool Inno.Editor.Interactions.EditorInteractions.ClosePanel(string panelId)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorInteractions.cs#L450) | Closes one panel in the active extension generation without toggling its current state.
`panelId`: The stable panel identifier to resolve. | true when an available panel was found. | `System.ArgumentException`: Thrown when panelId is empty. | | [`public sealed class Inno.Editor.Interactions.EditorModalExtension`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L11) | Describes one active modal extension. | — | — | | [`public string Inno.Editor.Interactions.EditorModalExtension.id { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L34) | Gets the stable modal identifier. | — | — | | [`public string Inno.Editor.Interactions.EditorModalExtension.title { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L39) | Gets the visible modal title. | — | — | | [`public int Inno.Editor.Interactions.EditorModalExtension.order { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L44) | Gets the stable modal ordering value. | — | — | -| [`public bool Inno.Editor.Interactions.EditorModalExtension.TryGetPresentation(out Inno.Editor.Interactions.EditorModalExtension.Presentation presentation)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L55) | Safely captures generation-local modal presentation values.
`presentation`: The captured immutable presentation, or its default value when the modal is quarantined. | when every presentation value was read successfully. | — | -| [`public bool Inno.Editor.Interactions.EditorModalExtension.Draw(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L95) | Safely draws the modal body and quarantines a failing extension instance.
`context`: The active editor context supplied by the presentation backend. | when the modal completed drawing without being quarantined. | `System.ArgumentNullException`: Thrown when is . | -| [`public readonly record struct Inno.Editor.Interactions.EditorModalExtension.Presentation : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L116) | Stores immutable modal window policy values read from one extension generation. | — | — | -| [`public Inno.Editor.Interactions.EditorModalExtension.Presentation.Presentation(bool isVisible, bool blocksInteraction, bool canMove, bool canResize, bool allowScrolling, System.Numerics.Vector2 initialSize, System.Numerics.Vector2 minimumSize)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L142) | Creates an immutable modal presentation snapshot.
`isVisible`: Whether the modal should currently be visible.
`blocksInteraction`: Whether the modal blocks regular editor interaction.
`canMove`: Whether the modal window can be moved.
`canResize`: Whether the modal window can be resized.
`allowScrolling`: Whether the modal window owns overflow scrolling.
`initialSize`: The initial size in unscaled editor units.
`minimumSize`: The minimum size in unscaled editor units. | — | — | -| [`public bool Inno.Editor.Interactions.EditorModalExtension.Presentation.isVisible { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L163) | Gets whether the modal should currently be visible. | — | — | -| [`public bool Inno.Editor.Interactions.EditorModalExtension.Presentation.blocksInteraction { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L168) | Gets whether the modal blocks regular editor interaction. | — | — | -| [`public bool Inno.Editor.Interactions.EditorModalExtension.Presentation.canMove { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L173) | Gets whether the modal window can be moved. | — | — | -| [`public bool Inno.Editor.Interactions.EditorModalExtension.Presentation.canResize { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L178) | Gets whether the modal window can be resized. | — | — | -| [`public bool Inno.Editor.Interactions.EditorModalExtension.Presentation.allowScrolling { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L183) | Gets whether overflow scrolling belongs to the modal window. | — | — | -| [`public System.Numerics.Vector2 Inno.Editor.Interactions.EditorModalExtension.Presentation.initialSize { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L188) | Gets the initial size in unscaled editor units. | — | — | -| [`public System.Numerics.Vector2 Inno.Editor.Interactions.EditorModalExtension.Presentation.minimumSize { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L193) | Gets the minimum size in unscaled editor units. | — | — | -| [`public override string Inno.Editor.Interactions.EditorModalExtension.Presentation.ToString()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L116) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | -| [`public static bool Inno.Editor.Interactions.EditorModalExtension.Presentation.operator !=(Inno.Editor.Interactions.EditorModalExtension.Presentation left, Inno.Editor.Interactions.EditorModalExtension.Presentation right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L116) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.Interactions.EditorModalExtension.Presentation.operator ==(Inno.Editor.Interactions.EditorModalExtension.Presentation left, Inno.Editor.Interactions.EditorModalExtension.Presentation right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L116) | Inherited or compiler-provided contract. | — | — | -| [`public override int Inno.Editor.Interactions.EditorModalExtension.Presentation.GetHashCode()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L116) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.Interactions.EditorModalExtension.Presentation.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L116) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.Interactions.EditorModalExtension.Presentation.Equals(Inno.Editor.Interactions.EditorModalExtension.Presentation other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L116) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | +| [`public bool Inno.Editor.Interactions.EditorModalExtension.TryPrepare(Inno.Editor.Core.EditorContext context, Inno.Editor.Interactions.EditorModalExtension.Presentation presentation, System.Numerics.Vector2 availableContentSize, out System.Numerics.Vector2? contentSize)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L67) | Prepares one presentation frame, quarantining failures before a native window is opened.
`context`: The active owner-thread context.
`presentation`: The window policy already captured for this presentation attempt.
`availableContentSize`: The bounded content size in current presentation coordinates.
`contentSize`: The measured extent, or null for explicit sizing or failed preparation. | True when preparation succeeded; false when this extension is quarantined. | `System.ArgumentNullException`: The context is null. | +| [`public bool Inno.Editor.Interactions.EditorModalExtension.TryGetPresentation(out Inno.Editor.Interactions.EditorModalExtension.Presentation presentation)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L105) | Safely captures generation-local modal presentation values.
`presentation`: The captured immutable presentation, or its default value when the modal is quarantined. | true when every presentation value was read successfully. | — | +| [`public bool Inno.Editor.Interactions.EditorModalExtension.Draw(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L145) | Safely draws the modal body and quarantines a failing extension instance.
`context`: The active editor context supplied by the presentation backend. | true when the modal completed drawing without being quarantined. | `System.ArgumentNullException`: Thrown when context is null. | +| [`public readonly record struct Inno.Editor.Interactions.EditorModalExtension.Presentation : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L166) | Stores immutable modal window policy values read from one extension generation. | — | — | +| [`public Inno.Editor.Interactions.EditorModalExtension.Presentation.Presentation(bool isVisible, bool blocksInteraction, bool canMove, bool canResize, bool allowScrolling, System.Numerics.Vector2 initialSize, System.Numerics.Vector2 minimumSize)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L192) | Creates an immutable modal presentation snapshot.
`isVisible`: Whether the modal should currently be visible.
`blocksInteraction`: Whether the modal blocks regular editor interaction.
`canMove`: Whether the modal window can be moved.
`canResize`: Whether the modal window can be resized.
`allowScrolling`: Whether the modal window owns overflow scrolling.
`initialSize`: The initial size in unscaled editor units.
`minimumSize`: The minimum size in unscaled editor units. | — | — | +| [`public bool Inno.Editor.Interactions.EditorModalExtension.Presentation.isVisible { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L213) | Gets whether the modal should currently be visible. | — | — | +| [`public bool Inno.Editor.Interactions.EditorModalExtension.Presentation.blocksInteraction { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L218) | Gets whether the modal blocks regular editor interaction. | — | — | +| [`public bool Inno.Editor.Interactions.EditorModalExtension.Presentation.canMove { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L223) | Gets whether the modal window can be moved. | — | — | +| [`public bool Inno.Editor.Interactions.EditorModalExtension.Presentation.canResize { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L228) | Gets whether the modal window can be resized. | — | — | +| [`public bool Inno.Editor.Interactions.EditorModalExtension.Presentation.allowScrolling { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L233) | Gets whether overflow scrolling belongs to the modal window. | — | — | +| [`public System.Numerics.Vector2 Inno.Editor.Interactions.EditorModalExtension.Presentation.initialSize { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L238) | Gets the initial size in unscaled editor units. | — | — | +| [`public System.Numerics.Vector2 Inno.Editor.Interactions.EditorModalExtension.Presentation.minimumSize { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L243) | Gets the minimum size in unscaled editor units. | — | — | +| [`public override string Inno.Editor.Interactions.EditorModalExtension.Presentation.ToString()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L166) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | +| [`public static bool Inno.Editor.Interactions.EditorModalExtension.Presentation.operator !=(Inno.Editor.Interactions.EditorModalExtension.Presentation left, Inno.Editor.Interactions.EditorModalExtension.Presentation right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L166) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Interactions.EditorModalExtension.Presentation.operator ==(Inno.Editor.Interactions.EditorModalExtension.Presentation left, Inno.Editor.Interactions.EditorModalExtension.Presentation right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L166) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public override int Inno.Editor.Interactions.EditorModalExtension.Presentation.GetHashCode()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L166) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | +| [`public override bool Inno.Editor.Interactions.EditorModalExtension.Presentation.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L166) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Interactions.EditorModalExtension.Presentation.Equals(Inno.Editor.Interactions.EditorModalExtension.Presentation other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs#L166) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | | [`public sealed class Inno.Editor.Interactions.EditorPanelExtension`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorPanelExtension.cs#L11) | Describes one active dockable panel extension. | — | — | | [`public string Inno.Editor.Interactions.EditorPanelExtension.id { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorPanelExtension.cs#L37) | Gets the stable panel identifier. | — | — | | [`public string Inno.Editor.Interactions.EditorPanelExtension.title { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorPanelExtension.cs#L42) | Gets the visible panel title. | — | — | | [`public int Inno.Editor.Interactions.EditorPanelExtension.order { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorPanelExtension.cs#L47) | Gets the stable panel ordering value. | — | — | | [`public bool Inno.Editor.Interactions.EditorPanelExtension.isOpen { get; set; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorPanelExtension.cs#L52) | Gets or sets whether this panel is open in the current extension generation. | — | — | -| [`public bool Inno.Editor.Interactions.EditorPanelExtension.TakeFocusRequest()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorPanelExtension.cs#L64) | Consumes a pending request to focus this panel window. | once for each accepted focus request. | — | -| [`public bool Inno.Editor.Interactions.EditorPanelExtension.TryGetWindowPresentation(out bool useWindowPadding, out bool allowScrolling, out System.Numerics.Vector2 initialSize)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorPanelExtension.cs#L81) | Safely reads the panel window-presentation policy through the active extension boundary.
`useWindowPadding`: The requested padding policy, or the safe default when the panel is quarantined.
`allowScrolling`: The requested scrolling policy, or the safe default when the panel is quarantined.
`initialSize`: The preferred first-use floating size, or zero when native sizing is requested. | when the policy was read without quarantining the panel. | — | -| [`public bool Inno.Editor.Interactions.EditorPanelExtension.Draw(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorPanelExtension.cs#L118) | Safely draws the panel body and quarantines a failing extension instance.
`context`: The active editor context supplied by the presentation backend. | when the panel completed drawing without being quarantined. | `System.ArgumentNullException`: Thrown when is . | +| [`public bool Inno.Editor.Interactions.EditorPanelExtension.TakeFocusRequest()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorPanelExtension.cs#L64) | Consumes a pending request to focus this panel window. | true once for each accepted focus request. | — | +| [`public bool Inno.Editor.Interactions.EditorPanelExtension.TryGetWindowPresentation(out bool useWindowPadding, out bool allowScrolling, out System.Numerics.Vector2 initialSize)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorPanelExtension.cs#L81) | Safely reads the panel window-presentation policy through the active extension boundary.
`useWindowPadding`: The requested padding policy, or the safe default when the panel is quarantined.
`allowScrolling`: The requested scrolling policy, or the safe default when the panel is quarantined.
`initialSize`: The preferred first-use floating size, or zero when native sizing is requested. | true when the policy was read without quarantining the panel. | — | +| [`public bool Inno.Editor.Interactions.EditorPanelExtension.Draw(Inno.Editor.Core.EditorContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorPanelExtension.cs#L118) | Safely draws the panel body and quarantines a failing extension instance.
`context`: The active editor context supplied by the presentation backend. | true when the panel completed drawing without being quarantined. | `System.ArgumentNullException`: Thrown when context is null. | | [`public interface Inno.Editor.Interactions.IEditorSelectionCoordinator`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/IEditorSelectionCoordinator.cs#L10) | Coordinates host-owned selection and the Core identity lifetime of temporary presentations. | — | — | -| [`System.IDisposable Inno.Editor.Interactions.IEditorSelectionCoordinator.RegisterIdentityDomain(Inno.Core.Identity.IdentityAllocator allocator)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/IEditorSelectionCoordinator.cs#L31) | Registers the Core identity domain used by a temporary scene presentation.
`allocator`: The borrowed allocator owned by that presentation's runtime session. | A routing lease released after restoring the preceding selection. | `System.ArgumentNullException`: The allocator is null.
`System.InvalidOperationException`: The domain is already active or the caller is not the owner thread.
`System.ObjectDisposedException`: The coordinator has retired. | -| [`object? Inno.Editor.Interactions.IEditorSelectionCoordinator.selectedTarget { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/IEditorSelectionCoordinator.cs#L36) | Gets the currently selected target, or when selection is empty. | — | — | -| [`void Inno.Editor.Interactions.IEditorSelectionCoordinator.SetSelection(object? target)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/IEditorSelectionCoordinator.cs#L44) | Replaces the current target after closing presentations owned by another target.
`target`: The new target, or to clear selection. | — | — | +| [`System.IDisposable Inno.Editor.Interactions.IEditorSelectionCoordinator.RegisterIdentityDomain(Inno.Core.Identity.IdentityAllocator allocator)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/IEditorSelectionCoordinator.cs#L31) | Registers the Core identity domain used by a temporary scene presentation.
`allocator`: The borrowed allocator owned by that presentation's runtime session. | A routing lease released after restoring the preceding selection. | `System.ArgumentNullException`: The allocator is null.
`System.InvalidOperationException`: The domain is already active or the caller is not the owner thread.
`System.ObjectDisposedException`: The coordinator has retired. | +| [`object? Inno.Editor.Interactions.IEditorSelectionCoordinator.selectedTarget { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/IEditorSelectionCoordinator.cs#L36) | Gets the currently selected target, or null when selection is empty. | — | — | +| [`void Inno.Editor.Interactions.IEditorSelectionCoordinator.SetSelection(object? target)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Runtime/IEditorSelectionCoordinator.cs#L44) | Replaces the current target after closing presentations owned by another target.
`target`: The new target, or null to clear selection. | — | — | | [`public sealed class Inno.Editor.Interactions.EditorSelectionSnapshot`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionSnapshot.cs#L10) | Captures ordered selection identities without retaining any domain object or extension instance. | — | — | | [`public System.Collections.Generic.IReadOnlyList Inno.Editor.Interactions.EditorSelectionSnapshot.identities { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionSnapshot.cs#L25) | Gets unique selection identities in order; the final identity is the primary selection. | — | — | | [`public Inno.Core.Identity.RuntimeIdentity? Inno.Editor.Interactions.EditorSelectionSnapshot.anchor { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionSnapshot.cs#L29) | Gets the range anchor identity, or null when there is no registered anchor. | — | — | -| [`public int Inno.Editor.Interactions.EditorSelectionSnapshot.CopyTargets(Inno.Editor.Interactions.EditorInteractions interactions, System.Collections.Generic.ICollection destination) where TTarget : class`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionSnapshot.cs#L46) | Resolves this immutable selection in its original domains, including same-identity recovery after a generation change.
`interactions`: The active session supplying the original identity domains.
`destination`: A temporary caller-owned collection to clear and fill.
`TTarget`: The target type accepted by the current presenter. | The number of currently available compatible targets; missing members remain represented by this snapshot. | — | +| [`public int Inno.Editor.Interactions.EditorSelectionSnapshot.CopyTargets(Inno.Editor.Interactions.EditorInteractions interactions, System.Collections.Generic.ICollection destination) where TTarget : class`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionSnapshot.cs#L46) | Resolves this immutable selection in its original domains, including same-identity recovery after a generation change.
`TTarget`: The target type accepted by the current presenter.
`interactions`: The active session supplying the original identity domains.
`destination`: A temporary caller-owned collection to clear and fill. | The number of currently available compatible targets; missing members remain represented by this snapshot. | — | | [`public Inno.Core.Identity.RuntimeIdentity? Inno.Editor.Interactions.EditorSelectionSnapshot.primary { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionSnapshot.cs#L64) | Gets the primary identity, or null when this snapshot contains no registered targets. | — | — | | [`public sealed class Inno.Editor.Interactions.EditorSelectionState`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionState.cs#L10) | Owns ordered transient selection through domain-qualified identities instead of retaining live objects. | — | — | | [`public object? Inno.Editor.Interactions.EditorSelectionState.selectedTarget { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionState.cs#L25) | Gets the current primary target for this callback, or null when unavailable or unselected. | — | — | | [`public int Inno.Editor.Interactions.EditorSelectionState.count { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionState.cs#L29) | Gets the number of selected identities, including temporarily unavailable members. | — | — | | [`public object? Inno.Editor.Interactions.EditorSelectionState.anchor { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionState.cs#L33) | Gets the current range anchor, or null when the anchor is unavailable. | — | — | | [`public ulong Inno.Editor.Interactions.EditorSelectionState.version { get; private set; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionState.cs#L37) | Gets the selection revision, incremented only when membership, order or resolved generation changes. | — | — | -| [`public bool Inno.Editor.Interactions.EditorSelectionState.Contains(object? target)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionState.cs#L48) | Checks membership by the target's owning identity domain and generation.
`target`: The immediate target to inspect. | True when the target is a member of this selection. | — | -| [`public int Inno.Editor.Interactions.EditorSelectionState.CopyTargets(System.Collections.Generic.ICollection destination) where TTarget : class`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionState.cs#L78) | Copies currently available selected targets into a caller-owned temporary collection.
`destination`: The collection to clear and fill; do not retain live entries across callbacks.
`TTarget`: The target type accepted by the caller. | The number of targets resolved in this callback. | `System.ArgumentNullException`: The destination is null. | +| [`public bool Inno.Editor.Interactions.EditorSelectionState.Contains(object? target)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionState.cs#L48) | Checks membership by the target's owning identity domain and generation.
`target`: The immediate target to inspect. | True when the target is a member of this selection. | — | +| [`public int Inno.Editor.Interactions.EditorSelectionState.CopyTargets(System.Collections.Generic.ICollection destination) where TTarget : class`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionState.cs#L78) | Copies currently available selected targets into a caller-owned temporary collection.
`TTarget`: The target type accepted by the caller.
`destination`: The collection to clear and fill; do not retain live entries across callbacks. | The number of targets resolved in this callback. | `System.ArgumentNullException`: The destination is null. | | [`public Inno.Editor.Interactions.EditorSelectionSnapshot Inno.Editor.Interactions.EditorSelectionState.Capture()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionState.cs#L98) | Captures the ordered runtime identities without retaining their resolved objects. | An immutable callback-independent snapshot; resolve identities afresh before using targets. | — | -| [`public bool Inno.Editor.Interactions.EditorSelectionState.TryGet(out TTarget? target)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionState.cs#L117) | Resolves the primary selected target as the requested type for immediate use.
`target`: Receives the available primary target, or null.
`TTarget`: The expected target type. | True when the current primary target has the requested type. | — | +| [`public bool Inno.Editor.Interactions.EditorSelectionState.TryGet(out TTarget? target)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Selection/EditorSelectionState.cs#L117) | Resolves the primary selected target as the requested type for immediate use.
`TTarget`: The expected target type.
`target`: Receives the available primary target, or null. | True when the current primary target has the requested type. | — | | [`public enum Inno.Editor.Interactions.EditorToolbarIcon : int`](../../src/composition/editor/framework/Inno.Editor.Interactions/Toolbars/EditorToolbarIcon.cs#L6) | Identifies a presentation-independent symbol for an editor toolbar command. | — | — | | [`Inno.Editor.Interactions.EditorToolbarIcon.None = 0`](../../src/composition/editor/framework/Inno.Editor.Interactions/Toolbars/EditorToolbarIcon.cs#L11) | No symbol is requested. | — | — | | [`Inno.Editor.Interactions.EditorToolbarIcon.Play = 1`](../../src/composition/editor/framework/Inno.Editor.Interactions/Toolbars/EditorToolbarIcon.cs#L16) | Starts an operation or simulation. | — | — | @@ -1440,7 +1442,7 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`public int Inno.Editor.Interactions.EditorToolbarItem.order { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Toolbars/EditorToolbarItem.cs#L40) | Gets the stable ordering value. | — | — | | [`public Inno.Editor.Interactions.EditorActionState Inno.Editor.Interactions.EditorToolbarItem.status { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Toolbars/EditorToolbarItem.cs#L45) | Gets the current action availability and checked state. | — | — | | [`public sealed class Inno.Editor.Interactions.EditorToolbarItemAttribute : System.Attribute`](../../src/composition/editor/framework/Inno.Editor.Interactions/Toolbars/EditorToolbarItemAttribute.cs#L9) | Places an editor action on a compact toolbar surface. | — | — | -| [`public Inno.Editor.Interactions.EditorToolbarItemAttribute.EditorToolbarItemAttribute(string area, Inno.Editor.Interactions.EditorToolbarIcon icon, string tooltip, int order = 0, Inno.Editor.Interactions.EditorToolbarIcon activeIcon = Inno.Editor.Interactions.EditorToolbarIcon.None)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Toolbars/EditorToolbarItemAttribute.cs#L37) | Creates a toolbar placement for the annotated targetless action.
`area`: The exact interaction area whose toolbar receives the action.
`icon`: The symbol shown while the action is not checked.
`tooltip`: The fallback tooltip shown when the action has no contextual display name.
`order`: The stable ordering value within the toolbar.
`activeIcon`: The symbol shown while the action is checked, or to retain . | — | `System.ArgumentException`: Thrown when or is empty, or when is .
`System.ArgumentOutOfRangeException`: Thrown when an icon value is not defined. | +| [`public Inno.Editor.Interactions.EditorToolbarItemAttribute.EditorToolbarItemAttribute(string area, Inno.Editor.Interactions.EditorToolbarIcon icon, string tooltip, int order = 0, Inno.Editor.Interactions.EditorToolbarIcon activeIcon = Inno.Editor.Interactions.EditorToolbarIcon.None)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Toolbars/EditorToolbarItemAttribute.cs#L37) | Creates a toolbar placement for the annotated targetless action.
`area`: The exact interaction area whose toolbar receives the action.
`icon`: The symbol shown while the action is not checked.
`tooltip`: The fallback tooltip shown when the action has no contextual display name.
`order`: The stable ordering value within the toolbar.
`activeIcon`: The symbol shown while the action is checked, or F:Inno.Editor.Interactions.EditorToolbarIcon.None to retain icon. | — | `System.ArgumentException`: Thrown when area or tooltip is empty, or when icon is F:Inno.Editor.Interactions.EditorToolbarIcon.None.
`System.ArgumentOutOfRangeException`: Thrown when an icon value is not defined. | | [`public string Inno.Editor.Interactions.EditorToolbarItemAttribute.area { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Toolbars/EditorToolbarItemAttribute.cs#L65) | Gets the exact toolbar interaction area. | — | — | | [`public Inno.Editor.Interactions.EditorToolbarIcon Inno.Editor.Interactions.EditorToolbarItemAttribute.icon { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Toolbars/EditorToolbarItemAttribute.cs#L70) | Gets the symbol shown while the action is not checked. | — | — | | [`public Inno.Editor.Interactions.EditorToolbarIcon Inno.Editor.Interactions.EditorToolbarItemAttribute.activeIcon { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Toolbars/EditorToolbarItemAttribute.cs#L75) | Gets the optional replacement symbol shown while the action is checked. | — | — | @@ -1450,11 +1452,11 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`public System.Collections.Generic.IReadOnlyList Inno.Editor.Interactions.EditorToolbarModel.items { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Toolbars/EditorToolbarModel.cs#L18) | Gets visible toolbar commands in deterministic display order. | — | — | | [`public sealed class Inno.Editor.Interactions.EditorPlanarNavigation`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorPlanarNavigation.cs#L9) | Shares captured planar gestures and mouse-anchored zoom math between scene and graph canvases. | — | — | | [`public bool Inno.Editor.Interactions.EditorPlanarNavigation.isPanning { get; private set; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorPlanarNavigation.cs#L16) | Gets whether this canvas owns a pan gesture, including while the pointer is outside its bounds. | — | — | -| [`public bool Inno.Editor.Interactions.EditorPlanarNavigation.Update(bool hovered, bool primaryPressed, bool middlePressed, bool primaryDown, bool middleDown, bool alt, bool allowAltPrimary = true)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorPlanarNavigation.cs#L45) | Advances pointer capture using logical button state rather than window-local release events.
`hovered`: Whether a new gesture may start in this canvas.
`primaryPressed`: Whether the primary button was pressed this frame.
`middlePressed`: Whether the middle button was pressed this frame.
`primaryDown`: Current global primary button state.
`middleDown`: Current global middle button state.
`alt`: Whether Alt is held when the gesture starts.
`allowAltPrimary`: Whether Alt-primary belongs to pan rather than another navigation mode. | Whether this canvas owns the current pointer gesture. | — | +| [`public bool Inno.Editor.Interactions.EditorPlanarNavigation.Update(bool hovered, bool primaryPressed, bool middlePressed, bool primaryDown, bool middleDown, bool alt, bool allowAltPrimary = true)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorPlanarNavigation.cs#L45) | Advances pointer capture using logical button state rather than window-local release events.
`hovered`: Whether a new gesture may start in this canvas.
`primaryPressed`: Whether the primary button was pressed this frame.
`middlePressed`: Whether the middle button was pressed this frame.
`primaryDown`: Current global primary button state.
`middleDown`: Current global middle button state.
`alt`: Whether Alt is held when the gesture starts.
`allowAltPrimary`: Whether Alt-primary belongs to pan rather than another navigation mode. | Whether this canvas owns the current pointer gesture. | — | | [`public void Inno.Editor.Interactions.EditorPlanarNavigation.Cancel()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorPlanarNavigation.cs#L67) | Releases capture when a canvas closes or a gesture is cancelled. | — | — | -| [`public static float Inno.Editor.Interactions.EditorPlanarNavigation.WheelFactor(float wheel, float sensitivity = 0.16)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorPlanarNavigation.cs#L84) | Converts wheel input to the common exponential magnification used by Editor canvases.
`wheel`: Logical wheel units, independent of framebuffer DPI.
`sensitivity`: Positive exponential sensitivity. | A finite positive magnification factor; positive wheel magnifies content. | `System.ArgumentOutOfRangeException`: Input is non-finite or sensitivity is not positive. | -| [`public static System.Numerics.Vector2 Inno.Editor.Interactions.EditorPlanarNavigation.ZoomOrigin(System.Numerics.Vector2 origin, System.Numerics.Vector2 pivot, float previousScale, float nextScale)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorPlanarNavigation.cs#L116) | Changes the screen-space origin so zoom preserves the same content point beneath the cursor.
`origin`: Current logical-pixel content origin.
`pivot`: Logical-pixel cursor position relative to the canvas.
`previousScale`: Previous positive content magnification.
`nextScale`: New positive content magnification after clamping. | The origin preserving the pivot's content coordinate. | `System.ArgumentOutOfRangeException`: An input is non-finite or a scale is not positive. | -| [`public Inno.Editor.Interactions.EditorPlanarNavigation.EditorPlanarNavigation()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorPlanarNavigation.cs#L9) | Inherited or compiler-provided contract. | — | — | +| [`public static float Inno.Editor.Interactions.EditorPlanarNavigation.WheelFactor(float wheel, float sensitivity = 0.16)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorPlanarNavigation.cs#L84) | Converts wheel input to the common exponential magnification used by Editor canvases.
`wheel`: Logical wheel units, independent of framebuffer DPI.
`sensitivity`: Positive exponential sensitivity. | A finite positive magnification factor; positive wheel magnifies content. | `System.ArgumentOutOfRangeException`: Input is non-finite or sensitivity is not positive. | +| [`public static System.Numerics.Vector2 Inno.Editor.Interactions.EditorPlanarNavigation.ZoomOrigin(System.Numerics.Vector2 origin, System.Numerics.Vector2 pivot, float previousScale, float nextScale)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorPlanarNavigation.cs#L116) | Changes the screen-space origin so zoom preserves the same content point beneath the cursor.
`origin`: Current logical-pixel content origin.
`pivot`: Logical-pixel cursor position relative to the canvas.
`previousScale`: Previous positive content magnification.
`nextScale`: New positive content magnification after clamping. | The origin preserving the pivot's content coordinate. | `System.ArgumentOutOfRangeException`: An input is non-finite or a scale is not positive. | +| [`public Inno.Editor.Interactions.EditorPlanarNavigation.EditorPlanarNavigation()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorPlanarNavigation.cs#L9) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public enum Inno.Editor.Interactions.EditorViewportPointerPhase : int`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L10) | Selects the lifecycle phase of one viewport pointer sample. | — | — | | [`Inno.Editor.Interactions.EditorViewportPointerPhase.Down = 0`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L15) | The pointer button began a gesture. | — | — | | [`Inno.Editor.Interactions.EditorViewportPointerPhase.Move = 1`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L19) | The pointer moved or changed hover position. | — | — | @@ -1469,18 +1471,18 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`Inno.Editor.Interactions.EditorViewportCursor.ResizeVertical = 5`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L58) | Uses vertical resizing arrows. | — | — | | [`Inno.Editor.Interactions.EditorViewportCursor.Hidden = 6`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L62) | Hides the pointer while the tool owns it. | — | — | | [`public readonly record struct Inno.Editor.Interactions.EditorViewportShortcut : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L68) | Contains one presentation-independent shortcut sample for a focused viewport tool. | — | — | -| [`public Inno.Editor.Interactions.EditorViewportShortcut.EditorViewportShortcut(Inno.Core.Input.KeyCode key, Inno.Core.Input.KeyModifier modifiers = Inno.Core.Input.KeyModifier.None, bool repeat = false)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L82) | Creates one viewport shortcut sample.
`key`: Pressed key.
`modifiers`: Active keyboard modifiers.
`repeat`: Whether the platform generated an auto-repeat press. | — | — | +| [`public Inno.Editor.Interactions.EditorViewportShortcut.EditorViewportShortcut(Inno.Core.Input.KeyCode key, Inno.Core.Input.KeyModifier modifiers = Inno.Core.Input.KeyModifier.None, bool repeat = false)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L82) | Creates one viewport shortcut sample.
`key`: Pressed key.
`modifiers`: Active keyboard modifiers.
`repeat`: Whether the platform generated an auto-repeat press. | — | — | | [`public Inno.Core.Input.KeyCode Inno.Editor.Interactions.EditorViewportShortcut.key { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L95) | Gets the pressed key. | — | — | | [`public Inno.Core.Input.KeyModifier Inno.Editor.Interactions.EditorViewportShortcut.modifiers { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L100) | Gets active keyboard modifiers. | — | — | | [`public bool Inno.Editor.Interactions.EditorViewportShortcut.repeat { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L105) | Gets whether the shortcut is an auto-repeat press. | — | — | | [`public override string Inno.Editor.Interactions.EditorViewportShortcut.ToString()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L68) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | -| [`public static bool Inno.Editor.Interactions.EditorViewportShortcut.operator !=(Inno.Editor.Interactions.EditorViewportShortcut left, Inno.Editor.Interactions.EditorViewportShortcut right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L68) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.Interactions.EditorViewportShortcut.operator ==(Inno.Editor.Interactions.EditorViewportShortcut left, Inno.Editor.Interactions.EditorViewportShortcut right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L68) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.Interactions.EditorViewportShortcut.operator !=(Inno.Editor.Interactions.EditorViewportShortcut left, Inno.Editor.Interactions.EditorViewportShortcut right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L68) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Interactions.EditorViewportShortcut.operator ==(Inno.Editor.Interactions.EditorViewportShortcut left, Inno.Editor.Interactions.EditorViewportShortcut right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L68) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.Interactions.EditorViewportShortcut.GetHashCode()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L68) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.Interactions.EditorViewportShortcut.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L68) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.Interactions.EditorViewportShortcut.Equals(Inno.Editor.Interactions.EditorViewportShortcut other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L68) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | +| [`public override bool Inno.Editor.Interactions.EditorViewportShortcut.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L68) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Interactions.EditorViewportShortcut.Equals(Inno.Editor.Interactions.EditorViewportShortcut other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L68) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | | [`public readonly record struct Inno.Editor.Interactions.EditorViewportPointerEvent : System.IEquatable`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L111) | Contains one immutable viewport pointer sample in screen and world coordinates. | — | — | -| [`public Inno.Editor.Interactions.EditorViewportPointerEvent.EditorViewportPointerEvent(int pointerId, Inno.Editor.Interactions.EditorViewportPointerPhase phase, Inno.Core.Mathematics.Vector2 screenPosition, Inno.Core.Mathematics.Vector2 worldPosition, int button, Inno.Core.Input.KeyModifier modifiers)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L134) | Creates one viewport pointer sample.
`pointerId`: Platform pointer identity.
`phase`: Gesture lifecycle phase.
`screenPosition`: Viewport-local pixel position.
`worldPosition`: Corresponding world position.
`button`: Platform button number.
`modifiers`: Active keyboard modifiers. | — | — | +| [`public Inno.Editor.Interactions.EditorViewportPointerEvent.EditorViewportPointerEvent(int pointerId, Inno.Editor.Interactions.EditorViewportPointerPhase phase, Inno.Core.Mathematics.Vector2 screenPosition, Inno.Core.Mathematics.Vector2 worldPosition, int button, Inno.Core.Input.KeyModifier modifiers)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L134) | Creates one viewport pointer sample.
`pointerId`: Platform pointer identity.
`phase`: Gesture lifecycle phase.
`screenPosition`: Viewport-local pixel position.
`worldPosition`: Corresponding world position.
`button`: Platform button number.
`modifiers`: Active keyboard modifiers. | — | — | | [`public int Inno.Editor.Interactions.EditorViewportPointerEvent.pointerId { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L153) | Gets the platform pointer identity. | — | — | | [`public Inno.Editor.Interactions.EditorViewportPointerPhase Inno.Editor.Interactions.EditorViewportPointerEvent.phase { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L158) | Gets the gesture lifecycle phase. | — | — | | [`public Inno.Core.Mathematics.Vector2 Inno.Editor.Interactions.EditorViewportPointerEvent.screenPosition { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L163) | Gets the viewport-local pixel position. | — | — | @@ -1488,41 +1490,41 @@ Action 的延迟 target、focus 和选择均使用 Core Identity;执行前重 | [`public int Inno.Editor.Interactions.EditorViewportPointerEvent.button { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L173) | Gets the platform button number. | — | — | | [`public Inno.Core.Input.KeyModifier Inno.Editor.Interactions.EditorViewportPointerEvent.modifiers { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L178) | Gets active keyboard modifiers. | — | — | | [`public override string Inno.Editor.Interactions.EditorViewportPointerEvent.ToString()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L111) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | -| [`public static bool Inno.Editor.Interactions.EditorViewportPointerEvent.operator !=(Inno.Editor.Interactions.EditorViewportPointerEvent left, Inno.Editor.Interactions.EditorViewportPointerEvent right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L111) | Inherited or compiler-provided contract. | — | — | -| [`public static bool Inno.Editor.Interactions.EditorViewportPointerEvent.operator ==(Inno.Editor.Interactions.EditorViewportPointerEvent left, Inno.Editor.Interactions.EditorViewportPointerEvent right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L111) | Inherited or compiler-provided contract. | — | — | +| [`public static bool Inno.Editor.Interactions.EditorViewportPointerEvent.operator !=(Inno.Editor.Interactions.EditorViewportPointerEvent left, Inno.Editor.Interactions.EditorViewportPointerEvent right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L111) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Interactions.EditorViewportPointerEvent.operator ==(Inno.Editor.Interactions.EditorViewportPointerEvent left, Inno.Editor.Interactions.EditorViewportPointerEvent right)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L111) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public override int Inno.Editor.Interactions.EditorViewportPointerEvent.GetHashCode()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L111) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | -| [`public override bool Inno.Editor.Interactions.EditorViewportPointerEvent.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L111) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | if and this instance are the same type and represent the same value; otherwise, . | — | -| [`public bool Inno.Editor.Interactions.EditorViewportPointerEvent.Equals(Inno.Editor.Interactions.EditorViewportPointerEvent other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L111) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | if the current object is equal to the parameter; otherwise, . | — | +| [`public override bool Inno.Editor.Interactions.EditorViewportPointerEvent.Equals(object obj)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L111) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Interactions.EditorViewportPointerEvent.Equals(Inno.Editor.Interactions.EditorViewportPointerEvent other)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L111) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | | [`public interface Inno.Editor.Interactions.IEditorViewportCoordinateConverter`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L184) | Converts coordinates for one viewport camera without exposing its presentation backend. | — | — | -| [`Inno.Core.Mathematics.Vector2 Inno.Editor.Interactions.IEditorViewportCoordinateConverter.ScreenToWorld(Inno.Core.Mathematics.Vector2 screenPosition)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L195) | Converts viewport-local pixel coordinates to world coordinates.
`screenPosition`: Viewport-local pixel coordinates. | World coordinates. | — | -| [`Inno.Core.Mathematics.Vector2 Inno.Editor.Interactions.IEditorViewportCoordinateConverter.WorldToScreen(Inno.Core.Mathematics.Vector2 worldPosition)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L206) | Converts world coordinates to viewport-local pixel coordinates.
`worldPosition`: World coordinates. | Viewport-local pixel coordinates. | — | +| [`Inno.Core.Mathematics.Vector2 Inno.Editor.Interactions.IEditorViewportCoordinateConverter.ScreenToWorld(Inno.Core.Mathematics.Vector2 screenPosition)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L195) | Converts viewport-local pixel coordinates to world coordinates.
`screenPosition`: Viewport-local pixel coordinates. | World coordinates. | — | +| [`Inno.Core.Mathematics.Vector2 Inno.Editor.Interactions.IEditorViewportCoordinateConverter.WorldToScreen(Inno.Core.Mathematics.Vector2 worldPosition)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L206) | Converts world coordinates to viewport-local pixel coordinates.
`worldPosition`: World coordinates. | Viewport-local pixel coordinates. | — | | [`public abstract class Inno.Editor.Interactions.EditorViewportTool`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L212) | Defines one presentation-independent, reloadable viewport editing tool. | — | — | | [`public abstract string Inno.Editor.Interactions.EditorViewportTool.id { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L217) | Gets the globally stable tool identity. | — | — | | [`public virtual Inno.Editor.Interactions.EditorViewportCursor Inno.Editor.Interactions.EditorViewportTool.cursor { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L222) | Gets the cursor requested while this tool is active. | — | — | -| [`public virtual void Inno.Editor.Interactions.EditorViewportTool.OnPointerDown(Inno.Editor.Interactions.EditorViewportToolContext context, Inno.Editor.Interactions.EditorViewportPointerEvent pointer)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L233) | Handles a pointer press.
`context`: Gesture and coordinate context.
`pointer`: Immutable pointer sample. | — | — | -| [`public virtual void Inno.Editor.Interactions.EditorViewportTool.OnPointerMove(Inno.Editor.Interactions.EditorViewportToolContext context, Inno.Editor.Interactions.EditorViewportPointerEvent pointer)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L249) | Handles pointer movement or hover.
`context`: Gesture and coordinate context.
`pointer`: Immutable pointer sample. | — | — | -| [`public virtual void Inno.Editor.Interactions.EditorViewportTool.OnPointerUp(Inno.Editor.Interactions.EditorViewportToolContext context, Inno.Editor.Interactions.EditorViewportPointerEvent pointer)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L265) | Handles a pointer release.
`context`: Gesture and coordinate context.
`pointer`: Immutable pointer sample. | — | — | -| [`public virtual void Inno.Editor.Interactions.EditorViewportTool.OnPointerCancel(Inno.Editor.Interactions.EditorViewportToolContext context, Inno.Editor.Interactions.EditorViewportPointerEvent pointer)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L281) | Handles platform cancellation of an active gesture.
`context`: Gesture and coordinate context.
`pointer`: Immutable pointer sample. | — | — | -| [`public virtual bool Inno.Editor.Interactions.EditorViewportTool.OnShortcut(Inno.Editor.Interactions.EditorViewportToolContext context, Inno.Editor.Interactions.EditorViewportShortcut shortcut)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L302) | Handles a focused viewport shortcut before global action routing.
`context`: Gesture and coordinate context.
`shortcut`: Pressed key sample. | when the tool consumed the key. | — | -| [`public virtual void Inno.Editor.Interactions.EditorViewportTool.DrawOverlay(Inno.Editor.Interactions.EditorViewportToolContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L316) | Draws transient gizmos and diagnostics over the viewport.
`context`: Gesture and coordinate context. | — | — | -| [`protected Inno.Editor.Interactions.EditorViewportTool.EditorViewportTool()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L212) | Inherited or compiler-provided contract. | — | — | +| [`public virtual void Inno.Editor.Interactions.EditorViewportTool.OnPointerDown(Inno.Editor.Interactions.EditorViewportToolContext context, Inno.Editor.Interactions.EditorViewportPointerEvent pointer)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L233) | Handles a pointer press.
`context`: Gesture and coordinate context.
`pointer`: Immutable pointer sample. | — | — | +| [`public virtual void Inno.Editor.Interactions.EditorViewportTool.OnPointerMove(Inno.Editor.Interactions.EditorViewportToolContext context, Inno.Editor.Interactions.EditorViewportPointerEvent pointer)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L249) | Handles pointer movement or hover.
`context`: Gesture and coordinate context.
`pointer`: Immutable pointer sample. | — | — | +| [`public virtual void Inno.Editor.Interactions.EditorViewportTool.OnPointerUp(Inno.Editor.Interactions.EditorViewportToolContext context, Inno.Editor.Interactions.EditorViewportPointerEvent pointer)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L265) | Handles a pointer release.
`context`: Gesture and coordinate context.
`pointer`: Immutable pointer sample. | — | — | +| [`public virtual void Inno.Editor.Interactions.EditorViewportTool.OnPointerCancel(Inno.Editor.Interactions.EditorViewportToolContext context, Inno.Editor.Interactions.EditorViewportPointerEvent pointer)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L281) | Handles platform cancellation of an active gesture.
`context`: Gesture and coordinate context.
`pointer`: Immutable pointer sample. | — | — | +| [`public virtual bool Inno.Editor.Interactions.EditorViewportTool.OnShortcut(Inno.Editor.Interactions.EditorViewportToolContext context, Inno.Editor.Interactions.EditorViewportShortcut shortcut)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L302) | Handles a focused viewport shortcut before global action routing.
`context`: Gesture and coordinate context.
`shortcut`: Pressed key sample. | true when the tool consumed the key. | — | +| [`public virtual void Inno.Editor.Interactions.EditorViewportTool.DrawOverlay(Inno.Editor.Interactions.EditorViewportToolContext context)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L316) | Draws transient gizmos and diagnostics over the viewport.
`context`: Gesture and coordinate context. | — | — | +| [`protected Inno.Editor.Interactions.EditorViewportTool.EditorViewportTool()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportTool.cs#L212) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public sealed class Inno.Editor.Interactions.EditorViewportToolContext`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L8) | Coordinates pointer capture, transforms, and one history transaction for a viewport gesture. | — | — | | [`public bool Inno.Editor.Interactions.EditorViewportToolContext.hasPointerCapture { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L25) | Gets whether this tool owns a pointer. | — | — | -| [`public int? Inno.Editor.Interactions.EditorViewportToolContext.capturedPointerId { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L29) | Gets the captured pointer identity, or . | — | — | +| [`public int? Inno.Editor.Interactions.EditorViewportToolContext.capturedPointerId { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L29) | Gets the captured pointer identity, or null. | — | — | | [`public bool Inno.Editor.Interactions.EditorViewportToolContext.hasHistoryGesture { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L33) | Gets whether a history transaction is active for the current gesture. | — | — | -| [`public void Inno.Editor.Interactions.EditorViewportToolContext.CapturePointer(int pointerId)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L41) | Captures one pointer until explicit release or cancellation.
`pointerId`: Platform pointer identity. | — | — | +| [`public void Inno.Editor.Interactions.EditorViewportToolContext.CapturePointer(int pointerId)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L41) | Captures one pointer until explicit release or cancellation.
`pointerId`: Platform pointer identity. | — | — | | [`public void Inno.Editor.Interactions.EditorViewportToolContext.ReleasePointer()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L51) | Releases the currently captured pointer. | — | — | -| [`public void Inno.Editor.Interactions.EditorViewportToolContext.BeginHistoryGesture(string name)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L64) | Begins the only history transaction allowed for the current captured gesture.
`name`: User-facing Undo operation name. | — | — | -| [`public void Inno.Editor.Interactions.EditorViewportToolContext.CompleteHistoryGesture(bool commit)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L80) | Commits or rolls back the current gesture transaction exactly once.
`commit`: to commit; otherwise, roll back. | — | — | -| [`public Inno.Core.Mathematics.Vector2 Inno.Editor.Interactions.EditorViewportToolContext.ScreenToWorld(Inno.Core.Mathematics.Vector2 screenPosition)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L107) | Converts viewport-local pixel coordinates to world coordinates.
`screenPosition`: Viewport-local pixel coordinates. | World coordinates. | — | -| [`public Inno.Core.Mathematics.Vector2 Inno.Editor.Interactions.EditorViewportToolContext.WorldToScreen(Inno.Core.Mathematics.Vector2 worldPosition)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L117) | Converts world coordinates to viewport-local pixel coordinates.
`worldPosition`: World coordinates. | Viewport-local pixel coordinates. | — | +| [`public void Inno.Editor.Interactions.EditorViewportToolContext.BeginHistoryGesture(string name)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L64) | Begins the only history transaction allowed for the current captured gesture.
`name`: User-facing Undo operation name. | — | — | +| [`public void Inno.Editor.Interactions.EditorViewportToolContext.CompleteHistoryGesture(bool commit)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L80) | Commits or rolls back the current gesture transaction exactly once.
`commit`: true to commit; otherwise, roll back. | — | — | +| [`public Inno.Core.Mathematics.Vector2 Inno.Editor.Interactions.EditorViewportToolContext.ScreenToWorld(Inno.Core.Mathematics.Vector2 screenPosition)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L107) | Converts viewport-local pixel coordinates to world coordinates.
`screenPosition`: Viewport-local pixel coordinates. | World coordinates. | — | +| [`public Inno.Core.Mathematics.Vector2 Inno.Editor.Interactions.EditorViewportToolContext.WorldToScreen(Inno.Core.Mathematics.Vector2 worldPosition)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolContext.cs#L117) | Converts world coordinates to viewport-local pixel coordinates.
`worldPosition`: World coordinates. | Viewport-local pixel coordinates. | — | | [`public sealed class Inno.Editor.Interactions.EditorViewportToolSession : System.IDisposable`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolSession.cs#L8) | Routes focused viewport input to one active tool while enforcing pointer-capture ownership. | — | — | -| [`public Inno.Editor.Interactions.EditorViewportToolSession.EditorViewportToolSession(Inno.Editor.Interactions.IEditorHistory history, Inno.Editor.Interactions.IEditorViewportCoordinateConverter coordinates)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolSession.cs#L23) | Creates a viewport tool session.
`history`: History stack used by gesture transactions.
`coordinates`: Current viewport coordinate converter. | — | — | -| [`public Inno.Editor.Interactions.EditorViewportTool? Inno.Editor.Interactions.EditorViewportToolSession.tool { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolSession.cs#L33) | Gets the active tool, or . | — | — | +| [`public Inno.Editor.Interactions.EditorViewportToolSession.EditorViewportToolSession(Inno.Editor.Interactions.IEditorHistory history, Inno.Editor.Interactions.IEditorViewportCoordinateConverter coordinates)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolSession.cs#L23) | Creates a viewport tool session.
`history`: History stack used by gesture transactions.
`coordinates`: Current viewport coordinate converter. | — | — | +| [`public Inno.Editor.Interactions.EditorViewportTool? Inno.Editor.Interactions.EditorViewportToolSession.tool { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolSession.cs#L33) | Gets the active tool, or null. | — | — | | [`public Inno.Editor.Interactions.EditorViewportCursor Inno.Editor.Interactions.EditorViewportToolSession.cursor { get; }`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolSession.cs#L38) | Gets the requested cursor for the active tool. | — | — | -| [`public void Inno.Editor.Interactions.EditorViewportToolSession.SetTool(Inno.Editor.Interactions.EditorViewportTool? tool)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolSession.cs#L46) | Activates a tool after cancelling any current gesture.
`tool`: Tool to activate, or to deactivate. | — | — | -| [`public bool Inno.Editor.Interactions.EditorViewportToolSession.HandlePointer(Inno.Editor.Interactions.EditorViewportPointerEvent pointer)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolSession.cs#L64) | Routes one immutable pointer sample.
`pointer`: Pointer sample with precomputed world coordinates. | when an active tool accepted the sample. | — | -| [`public bool Inno.Editor.Interactions.EditorViewportToolSession.HandleShortcut(Inno.Editor.Interactions.EditorViewportShortcut shortcut)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolSession.cs#L97) | Routes one focused keyboard shortcut.
`shortcut`: Pressed key sample. | when consumed. | — | +| [`public void Inno.Editor.Interactions.EditorViewportToolSession.SetTool(Inno.Editor.Interactions.EditorViewportTool? tool)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolSession.cs#L46) | Activates a tool after cancelling any current gesture.
`tool`: Tool to activate, or null to deactivate. | — | — | +| [`public bool Inno.Editor.Interactions.EditorViewportToolSession.HandlePointer(Inno.Editor.Interactions.EditorViewportPointerEvent pointer)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolSession.cs#L64) | Routes one immutable pointer sample.
`pointer`: Pointer sample with precomputed world coordinates. | true when an active tool accepted the sample. | — | +| [`public bool Inno.Editor.Interactions.EditorViewportToolSession.HandleShortcut(Inno.Editor.Interactions.EditorViewportShortcut shortcut)`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolSession.cs#L97) | Routes one focused keyboard shortcut.
`shortcut`: Pressed key sample. | true when consumed. | — | | [`public void Inno.Editor.Interactions.EditorViewportToolSession.DrawOverlay()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolSession.cs#L106) | Draws the active tool overlay. | — | — | | [`public void Inno.Editor.Interactions.EditorViewportToolSession.Dispose()`](../../src/composition/editor/framework/Inno.Editor.Interactions/Viewport/EditorViewportToolSession.cs#L115) | Cancels active gesture state and deactivates the tool. | — | — | diff --git a/docs/editor/Inno.Editor.Scripting.md b/docs/editor/Inno.Editor.Scripting.md index 2b523c8b..783de325 100644 --- a/docs/editor/Inno.Editor.Scripting.md +++ b/docs/editor/Inno.Editor.Scripting.md @@ -248,10 +248,30 @@ Serialized state 使用逐成员兼容迁移:成员类型保持兼容时恢复 被拒绝的 `RequestCompilation` 返回失败 ticket,不替换当前已接受 ticket。成功 ticket 必须完成新代激活与旧代 Full GC/finalizers/Full GC 弱监测,不能以编译成功代替 Reload 成功。 +## 编译呈现快照 + +`IEditorScriptCompilation.progress` 返回 `EditorScriptCompilationProgress`,同时描述 operation ID、fraction、status、取消请求和当前取消能力。呈现只读取一次快照;`CancelCompilation(operationId)` 拒绝旧操作的按钮回调。operation ID 是本 Host 的瞬时请求序号,不是对象 Identity,也不参与持久化。 + +80% 表示编译阶段完成,之后仍需激活、恢复和严格 unload verification。成功完成不能早于退休屏障。后台编译观察者在编译阶段退出后停止发布;新的排队请求不接受旧请求的消息。 + ## 当前源码公开 API 清单 此清单对应当前 SDK 求值与源码符号;内部类型不构成公开 API。 + + + + + + + + + + + + + + @@ -259,12 +279,11 @@ Serialized state 使用逐成员兼容迁移:成员类型保持兼容时恢复 - - + + - @@ -280,8 +299,22 @@ Serialized state 使用逐成员兼容迁移:成员类型保持兼容时恢复 -| API 与源码 | 契约与参数 | 返回值 | 重要异常 | -| --- | --- | --- | --- | +| API | 职责与参数 | 返回语义 | 失败条件 | +|---|---|---|---| +| [`public readonly record struct Inno.Editor.Scripting.EditorScriptCompilationProgress : System.IEquatable`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs#L21) | Captures the progress and cancellation policy of one editor script request.
`operationId`: The request identity within the owning script host.
`fraction`: The completed fraction of the complete reload workflow.
`status`: The current stage or failure diagnostic.
`cancellationRequested`: Whether cancellation is draining owned work.
`canCancel`: Whether this exact operation currently admits cancellation. | — | — | +| [`public Inno.Editor.Scripting.EditorScriptCompilationProgress.EditorScriptCompilationProgress(long operationId, float fraction, string status, bool cancellationRequested, bool canCancel = false)`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs#L21) | Captures the progress and cancellation policy of one editor script request.
`operationId`: The request identity within the owning script host.
`fraction`: The completed fraction of the complete reload workflow.
`status`: The current stage or failure diagnostic.
`cancellationRequested`: Whether cancellation is draining owned work.
`canCancel`: Whether this exact operation currently admits cancellation. | — | — | +| [`public long Inno.Editor.Scripting.EditorScriptCompilationProgress.operationId { get; init; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs#L22) | The request identity within the owning script host. | — | — | +| [`public float Inno.Editor.Scripting.EditorScriptCompilationProgress.fraction { get; init; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs#L23) | The completed fraction of the complete reload workflow. | — | — | +| [`public string Inno.Editor.Scripting.EditorScriptCompilationProgress.status { get; init; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs#L24) | The current stage or failure diagnostic. | — | — | +| [`public bool Inno.Editor.Scripting.EditorScriptCompilationProgress.cancellationRequested { get; init; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs#L25) | Whether cancellation is draining owned work. | — | — | +| [`public bool Inno.Editor.Scripting.EditorScriptCompilationProgress.canCancel { get; init; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs#L26) | Whether this exact operation currently admits cancellation. | — | — | +| [`public override string Inno.Editor.Scripting.EditorScriptCompilationProgress.ToString()`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs#L21) | Returns the fully qualified type name of this instance. | The fully qualified type name. | — | +| [`public static bool Inno.Editor.Scripting.EditorScriptCompilationProgress.operator !=(Inno.Editor.Scripting.EditorScriptCompilationProgress left, Inno.Editor.Scripting.EditorScriptCompilationProgress right)`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs#L21) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Editor.Scripting.EditorScriptCompilationProgress.operator ==(Inno.Editor.Scripting.EditorScriptCompilationProgress left, Inno.Editor.Scripting.EditorScriptCompilationProgress right)`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs#L21) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public override int Inno.Editor.Scripting.EditorScriptCompilationProgress.GetHashCode()`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs#L21) | Returns the hash code for this instance. | A 32-bit signed integer that is the hash code for this instance. | — | +| [`public override bool Inno.Editor.Scripting.EditorScriptCompilationProgress.Equals(object obj)`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs#L21) | Indicates whether this instance and a specified object are equal.
`obj`: The object to compare with the current instance. | true if obj and this instance are the same type and represent the same value; otherwise, false. | — | +| [`public bool Inno.Editor.Scripting.EditorScriptCompilationProgress.Equals(Inno.Editor.Scripting.EditorScriptCompilationProgress other)`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs#L21) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | +| [`public void Inno.Editor.Scripting.EditorScriptCompilationProgress.Deconstruct(out long operationId, out float fraction, out string status, out bool cancellationRequested, out bool canCancel)`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs#L21) | 由 C# 编译器生成的值契约成员。 | — | — | | [`public enum Inno.Editor.Scripting.EditorScriptCompilationState : int`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L7) | Identifies whether the active project script generation can safely start game simulation. | — | — | | [`Inno.Editor.Scripting.EditorScriptCompilationState.Initializing = 0`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L12) | The script service has not produced its initial active generation. | — | — | | [`Inno.Editor.Scripting.EditorScriptCompilationState.Compiling = 1`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L16) | A requested script generation is compiling, activating, or completing unload verification. | — | — | @@ -289,18 +322,17 @@ Serialized state 使用逐成员兼容迁移:成员类型保持兼容时恢复 | [`Inno.Editor.Scripting.EditorScriptCompilationState.Failed = 3`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L24) | Compilation, activation, or generation retirement failed, so game simulation must not start. | — | — | | [`public interface Inno.Editor.Scripting.IEditorScriptCompilation`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L30) | Exposes the minimal script-generation readiness contract required by editor workflows. | — | — | | [`bool Inno.Editor.Scripting.IEditorScriptCompilation.requiresExclusiveProgress { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L35) | Gets whether compiler or activation work currently requires a blocking progress presentation. | — | — | -| [`float Inno.Editor.Scripting.IEditorScriptCompilation.progress { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L40) | Gets the most recent compiler progress fraction in the inclusive range zero to one. | — | — | -| [`void Inno.Editor.Scripting.IEditorScriptCompilation.CancelCompilation()`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L45) | Requests cancellation while retaining ownership until compilation and retirement finish. | — | — | -| [`Inno.Editor.Scripting.IScriptCompilationTicket Inno.Editor.Scripting.IEditorScriptCompilation.RequestCompilation()`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L53) | Queues a fresh cache-aware compilation for a build or simulation workflow. | A ticket bound to the exact request. Success requires activation and completed retirement verification; a faulted host returns a failed ticket and requires restart. | — | -| [`Inno.Editor.Scripting.IScriptCompilationTicket? Inno.Editor.Scripting.IEditorScriptCompilation.currentTicket { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L57) | Gets the most recently requested compilation ticket, or when no explicit request exists. | — | — | -| [`Inno.Editor.Scripting.EditorScriptCompilationState Inno.Editor.Scripting.IEditorScriptCompilation.state { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L62) | Gets the current script-generation readiness state. | — | — | -| [`string Inno.Editor.Scripting.IEditorScriptCompilation.status { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L67) | Gets a human-readable description of current compiler work or readiness. | — | — | -| [`Inno.Scripting.Compiler.ScriptCompilationResult? Inno.Editor.Scripting.IEditorScriptCompilation.lastCompilation { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L72) | Gets the most recently completed compilation, or before the first attempt completes. | — | — | +| [`Inno.Editor.Scripting.EditorScriptCompilationProgress Inno.Editor.Scripting.IEditorScriptCompilation.progress { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L40) | Gets one immutable snapshot of the current reload operation and its cancellation policy. | — | — | +| [`void Inno.Editor.Scripting.IEditorScriptCompilation.CancelCompilation(long operationId)`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L48) | Requests cancellation while retaining ownership until compilation and retirement finish.
`operationId`: The request observed by the presentation; stale requests have no effect. | — | — | +| [`Inno.Editor.Scripting.IScriptCompilationTicket Inno.Editor.Scripting.IEditorScriptCompilation.RequestCompilation()`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L56) | Queues a fresh cache-aware compilation for a build or simulation workflow. | A ticket bound to the exact request. Success requires activation and completed retirement verification; a faulted host returns a failed ticket and requires restart. | — | +| [`Inno.Editor.Scripting.IScriptCompilationTicket? Inno.Editor.Scripting.IEditorScriptCompilation.currentTicket { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L60) | Gets the most recently requested compilation ticket, or null when no explicit request exists. | — | — | +| [`Inno.Editor.Scripting.EditorScriptCompilationState Inno.Editor.Scripting.IEditorScriptCompilation.state { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L65) | Gets the current script-generation readiness state. | — | — | +| [`Inno.Scripting.Compiler.ScriptCompilationResult? Inno.Editor.Scripting.IEditorScriptCompilation.lastCompilation { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs#L71) | Gets the most recently completed compilation, or null before the first attempt completes. | — | — | | [`public interface Inno.Editor.Scripting.IScriptCompilationTicket`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IScriptCompilationTicket.cs#L8) | Exposes the immutable observer view of one exact script compilation and activation request. | — | — | | [`long Inno.Editor.Scripting.IScriptCompilationTicket.requestId { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IScriptCompilationTicket.cs#L13) | Gets the producer-local monotonic identifier of this request. | — | — | | [`Inno.Editor.Scripting.ScriptCompilationTicketState Inno.Editor.Scripting.IScriptCompilationTicket.state { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IScriptCompilationTicket.cs#L18) | Gets the current lifecycle state of this exact request. | — | — | | [`string Inno.Editor.Scripting.IScriptCompilationTicket.status { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IScriptCompilationTicket.cs#L23) | Gets a human-readable description of the current or terminal state. | — | — | -| [`Inno.Scripting.Compiler.ScriptCompilationResult? Inno.Editor.Scripting.IScriptCompilationTicket.result { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IScriptCompilationTicket.cs#L28) | Gets the completed compiler result, or before the compiler finishes. | — | — | +| [`Inno.Scripting.Compiler.ScriptCompilationResult? Inno.Editor.Scripting.IScriptCompilationTicket.result { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IScriptCompilationTicket.cs#L28) | Gets the completed compiler result, or null before the compiler finishes. | — | — | | [`bool Inno.Editor.Scripting.IScriptCompilationTicket.isCompleted { get; }`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/IScriptCompilationTicket.cs#L33) | Gets whether no further state transition is valid for this request. | — | — | | [`public enum Inno.Editor.Scripting.ScriptCompilationTicketState : int`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/ScriptCompilationTicketState.cs#L6) | Identifies the lifecycle state of one exact script compilation request. | — | — | | [`Inno.Editor.Scripting.ScriptCompilationTicketState.Queued = 0`](../../src/composition/editor/features/Inno.Editor.Scripting/Runtime/ScriptCompilationTicketState.cs#L11) | The request is queued behind the active compiler operation. | — | — | diff --git a/docs/scripting/Inno.Scripting.Reload.md b/docs/scripting/Inno.Scripting.Reload.md index 6add4ddf..52d2311b 100644 --- a/docs/scripting/Inno.Scripting.Reload.md +++ b/docs/scripting/Inno.Scripting.Reload.md @@ -31,37 +31,31 @@ candidate、Plugin uninstall、显式 unload 和 shutdown 都受同一规则约 自动编译只排除本 ScriptReloadHost 同步发布候选时产生的 SourceMountsChanged 通知回声。Assembly Catalog 会在每次脚本发布时重新发布隔离 Asset Catalog,这不是一次新的源文件编辑,不能由此排队下一轮 reload。真实文件变化、显式编译请求和外部 source-mount 发布仍然正常入队;不关闭 watcher、不取消全局通知,也不跳过 GC barrier。 -## 当前源码公开 API 清单 +## 操作进度与取消 + +`ScriptReloadHost.progress` 是通过一次原子发布获得的 `ScriptReloadProgress`。排队、后台编译、候选应用及退休各自带着同一请求身份;下一请求及其进度不会被旧请求或旧阶段的迟到回调覆盖。`CancelCompilation(operationId)` 在同一 owner 锁内校验身份,并在发出取消信号前发布取消状态。 -按类型列出当前 public 与可供外部派生实现使用的 protected 声明。签名包含 nullable、默认参数和泛型约束;源码链接可定位实现。表中的“—”表示该声明没有额外 XML 约束,不能据此推断线程安全或不会失败。生命周期与组合顺序见本页前文。 +进度只观察既有流程,不改变候选发布、Missing、GC/finalizer/weak-monitor 或 Faulted 协议。`canCancel` 来自实际编译阶段和资源所有权,不由百分比推测。已捕获快照不可变,不携带 Type、delegate 或插件实例。 -### `Inno.Scripting.Reload.IScriptReloadCoordinator` +## 当前源码公开 API 清单 + +此清单对应当前 SDK 求值与源码符号;内部类型不构成公开 API。 - -| 声明 | 行为与结果 | 所有权 / 调用约束 | 失败或限制 | -| --- | --- | --- | --- | -| [`Inno.Extensibility.Reload.IAssemblyUnloadProbe Inno.Scripting.Reload.IScriptReloadCoordinator.Execute(Inno.Extensibility.Modules.AssemblyReloadSession reload, Inno.Extensibility.Reload.IGenerationChange? externalChange = null)`](../../src/runtime/scripting/Inno.Scripting.Reload/IScriptReloadCoordinator.cs#L24) | Commits a prepared assembly reload together with dependent host state.
返回:A monitor observing cooperative unload of assemblies retired by the committed generation.
`reload`:The prepared assembly reload session to activate and complete.
`externalChange`:Optional five-phase content change; captured before publication and restored before domain property recovery. | — | — | -| [`void Inno.Scripting.Reload.IScriptReloadCoordinator.RefreshDiagnostics()`](../../src/runtime/scripting/Inno.Scripting.Reload/IScriptReloadCoordinator.cs#L32) | Requests diagnostics derived from the active host generation to be republished. | — | — | -| [`public interface Inno.Scripting.Reload.IScriptReloadCoordinator`](../../src/runtime/scripting/Inno.Scripting.Reload/IScriptReloadCoordinator.cs#L10) | Coordinates host-owned state with an atomic script assembly generation transition. | — | — | - -### `Inno.Scripting.Reload.ScriptReloadHost` - - - + - + @@ -70,33 +64,6 @@ candidate、Plugin uninstall、显式 unload 和 shutdown 都受同一规则约 - -| 声明 | 行为与结果 | 所有权 / 调用约束 | 失败或限制 | -| --- | --- | --- | --- | -| [`public Inno.Scripting.Reload.ScriptReloadHost.ScriptReloadHost(Inno.Scripting.Reload.ScriptReloadOptions options, Inno.Scripting.Compiler.ScriptCompiler compiler, Inno.Assets.Pipeline.AssetPipeline assets, Inno.Plugins.Authoring.PluginEnvironment plugins, Inno.Extensibility.Modules.ModuleHost modules, Inno.Core.Settings.ProjectSettingsStore settings, Inno.Scripting.Reload.IScriptReloadCoordinator reloads, System.Func moduleSourceFactory)`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L101) | Creates a reload host for one compiler and runtime module owner.
`options`:The automatic compilation, debounce, and long-running warning policy.
`compiler`:The compiler that produces immutable candidate script generations.
`assets`:The authoring asset pipeline that supplies committed source artifacts.
`plugins`:The Plugin environment that owns active and candidate source generations.
`modules`:The module host that atomically activates compiled assemblies.
`settings`:The project settings store rebuilt with each committed Plugin generation.
`reloads`:The host-owned coordinator that commits dependent state together with script generations.
`moduleSourceFactory`:The composition-owned factory that chooses the loading policy for each immutable script module. It must return a fresh source without activating or publishing the module. | — | `System.ArgumentNullException`:Thrown when any required dependency is null.
`System.ArgumentOutOfRangeException`:Thrown when the configured debounce duration is negative. | -| [`public bool Inno.Scripting.Reload.ScriptReloadHost.AdvanceUnloadVerification(out System.Exception? failure)`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L663) | Advances cooperative unload verification for retired script generations.
返回:true when no additional verification frame is required.
`failure`:Receives the retention failure after all verification attempts, otherwise null. | — | — | -| [`public bool Inno.Scripting.Reload.ScriptReloadHost.ApplyPendingReload()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L505) | Applies the latest compiled generation, or commits a Plugin-unavailability generation when changed Plugin code cannot produce a replacement, at a caller-controlled main-thread safe point.
返回:true when modules were replaced or retired; otherwise, false. | — | `System.ObjectDisposedException`:Thrown after the manager has been disposed. | -| [`public bool Inno.Scripting.Reload.ScriptReloadHost.CancelCompilation()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L296) | Requests cancellation of the active compilation without changing the active script generation.
返回:true when an active compilation received the request. | — | `System.ObjectDisposedException`:Thrown after the manager has been disposed. | -| [`public void Inno.Scripting.Reload.ScriptReloadHost.Dispose()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L586) | Cancels and waits for active compilation work, stops Asset Database observation, and unloads the active script module. | — | — | -| [`public void Inno.Scripting.Reload.ScriptReloadHost.GenerateProjectFiles()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L571) | Generates standard SDK-style game/editor projects and a solution for IDE tooling. | — | `System.ObjectDisposedException`:Thrown after the manager has been disposed. | -| [`public void Inno.Scripting.Reload.ScriptReloadHost.RecompileScripting()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L322) | Queues incremental recompilation of changed script assemblies. | — | `System.ObjectDisposedException`:Thrown after the manager has been disposed. | -| [`public void Inno.Scripting.Reload.ScriptReloadHost.ReloadPlugins()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L343) | Queues replacement of the unified plugin generation and both dependent scripting generations. Valid script artifacts are reused when plugin reference fingerprints are unchanged. | — | `System.ObjectDisposedException`:Thrown after the manager has been disposed. | -| [`public void Inno.Scripting.Reload.ScriptReloadHost.ReloadScripting()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L334) | Queues a complete rebuild of both scripting load contexts while retaining the plugin generation. Valid cached artifacts are reused. | — | `System.ObjectDisposedException`:Thrown after the manager has been disposed. | -| [`public void Inno.Scripting.Reload.ScriptReloadHost.Start()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L257) | Subscribes to committed asset changes and queues a cache-aware initial compilation request. | — | — | -| [`public bool Inno.Scripting.Reload.ScriptReloadHost.TryCompilePending(out System.Threading.Tasks.Task? compilation)`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L357) | Starts a pending compilation after the configured quiet period has elapsed.
返回:true when a pending compilation was started.
`compilation`:The started compilation task, or null when none was ready. | The initial automatic request is immediately ready and does not observe the debounce duration. | — | -| [`public System.TimeSpan Inno.Scripting.Reload.ScriptReloadHost.compilationElapsed { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L199) | Gets the elapsed duration of the active or most recently completed compilation. | — | — | -| [`public float Inno.Scripting.Reload.ScriptReloadHost.compilationProgress { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L180) | Gets the current compilation progress in the inclusive range from zero to one. | — | — | -| [`public string Inno.Scripting.Reload.ScriptReloadHost.compilationStatus { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L185) | Gets a short description of the current compilation stage. | — | — | -| [`public bool Inno.Scripting.Reload.ScriptReloadHost.isCompilationPending { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L168) | Gets whether source or plugin changes are waiting to be compiled. | — | — | -| [`public bool Inno.Scripting.Reload.ScriptReloadHost.isCompilationTakingLong { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L213) | Gets whether the active compilation exceeded the configured warning duration. | — | — | -| [`public bool Inno.Scripting.Reload.ScriptReloadHost.isCompiling { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L163) | Gets whether a compilation currently owns the compiler gate. | — | — | -| [`public bool Inno.Scripting.Reload.ScriptReloadHost.isFaulted { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L245) | Gets whether a retired generation exceeded the retention threshold and permanently stopped this host. | — | — | -| [`public bool Inno.Scripting.Reload.ScriptReloadHost.isUnloadVerificationPending { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L233) | Gets whether retired collectible assembly generations are still being verified for unload. | — | — | -| [`public Inno.Scripting.Compiler.ScriptCompilationResult? Inno.Scripting.Reload.ScriptReloadHost.lastCompilation { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L221) | Gets the most recently completed compilation. | — | — | -| [`public sealed class Inno.Scripting.Reload.ScriptReloadHost : System.IDisposable`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L24) | Watches, compiles, and atomically activates one project's C# script assemblies. | — | — | - -### `Inno.Scripting.Reload.ScriptReloadOptions` - @@ -104,16 +71,67 @@ candidate、Plugin uninstall、显式 unload 和 shutdown 都受同一规则约 - -| 声明 | 行为与结果 | 所有权 / 调用约束 | 失败或限制 | -| --- | --- | --- | --- | -| [`public Inno.Scripting.Reload.ScriptReloadOptions.ScriptReloadOptions()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadOptions.cs#L7) | C# 隐式构造函数;按类型声明执行字段初始化和基类构造。 | — | — | -| [`public bool Inno.Scripting.Reload.ScriptReloadOptions.autoCompile { get; init; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadOptions.cs#L16) | Gets whether startup and subsequent source changes request automatic compilation. | The initial request starts immediately. Later change requests are consumed only at a focused Editor safe point after the configured debounce duration. | — | -| [`public System.TimeSpan Inno.Scripting.Reload.ScriptReloadOptions.compilationWarningTimeout { get; init; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadOptions.cs#L30) | Gets the elapsed duration after which an active compilation is reported as long-running. | Use System.Threading.Timeout.InfiniteTimeSpan to disable the warning. The warning never cancels compilation automatically. | — | + + + + + + + + + + + + + + + +| API | 职责与参数 | 返回语义 | 失败条件 | +|---|---|---|---| +| [`public interface Inno.Scripting.Reload.IScriptReloadCoordinator`](../../src/runtime/scripting/Inno.Scripting.Reload/IScriptReloadCoordinator.cs#L10) | Coordinates host-owned state with an atomic script assembly generation transition. | — | — | +| [`Inno.Extensibility.Reload.IAssemblyUnloadProbe Inno.Scripting.Reload.IScriptReloadCoordinator.Execute(Inno.Extensibility.Modules.AssemblyReloadSession reload, Inno.Extensibility.Reload.IGenerationChange? externalChange = null)`](../../src/runtime/scripting/Inno.Scripting.Reload/IScriptReloadCoordinator.cs#L24) | Commits a prepared assembly reload together with dependent host state.
`reload`: The prepared assembly reload session to activate and complete.
`externalChange`: Optional five-phase content change; captured before publication and restored before domain property recovery. | A monitor observing cooperative unload of assemblies retired by the committed generation. | — | +| [`void Inno.Scripting.Reload.IScriptReloadCoordinator.RefreshDiagnostics()`](../../src/runtime/scripting/Inno.Scripting.Reload/IScriptReloadCoordinator.cs#L32) | Requests diagnostics derived from the active host generation to be republished. | — | — | +| [`public sealed class Inno.Scripting.Reload.ScriptReloadHost : System.IDisposable`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L24) | Watches, compiles, and atomically activates one project's C# script assemblies. | — | — | +| [`public Inno.Scripting.Reload.ScriptReloadHost.ScriptReloadHost(Inno.Scripting.Reload.ScriptReloadOptions options, Inno.Scripting.Compiler.ScriptCompiler compiler, Inno.Assets.Pipeline.AssetPipeline assets, Inno.Plugins.Authoring.PluginEnvironment plugins, Inno.Extensibility.Modules.ModuleHost modules, Inno.Core.Settings.ProjectSettingsStore settings, Inno.Scripting.Reload.IScriptReloadCoordinator reloads, System.Func moduleSourceFactory)`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L104) | Creates a reload host for one compiler and runtime module owner.
`options`: The automatic compilation, debounce, and long-running warning policy.
`compiler`: The compiler that produces immutable candidate script generations.
`assets`: The authoring asset pipeline that supplies committed source artifacts.
`plugins`: The Plugin environment that owns active and candidate source generations.
`modules`: The module host that atomically activates compiled assemblies.
`settings`: The project settings store rebuilt with each committed Plugin generation.
`reloads`: The host-owned coordinator that commits dependent state together with script generations.
`moduleSourceFactory`: The composition-owned factory that chooses the loading policy for each immutable script module. It must return a fresh source without activating or publishing the module. | — | `System.ArgumentNullException`: Thrown when any required dependency is null.
`System.ArgumentOutOfRangeException`: Thrown when the configured debounce duration is negative. | +| [`public bool Inno.Scripting.Reload.ScriptReloadHost.isCompiling { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L166) | Gets whether a compilation currently owns the compiler gate. | — | — | +| [`public bool Inno.Scripting.Reload.ScriptReloadHost.isCompilationPending { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L171) | Gets whether source or plugin changes are waiting to be compiled. | — | — | +| [`public Inno.Scripting.Reload.ScriptReloadProgress Inno.Scripting.Reload.ScriptReloadHost.progress { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L183) | Gets one atomically published operation, fraction, stage and cancellation snapshot. | — | — | +| [`public System.TimeSpan Inno.Scripting.Reload.ScriptReloadHost.compilationElapsed { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L188) | Gets the elapsed duration of the active or most recently completed compilation. | — | — | +| [`public bool Inno.Scripting.Reload.ScriptReloadHost.isCompilationTakingLong { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L202) | Gets whether the active compilation exceeded the configured warning duration. | — | — | +| [`public Inno.Scripting.Compiler.ScriptCompilationResult? Inno.Scripting.Reload.ScriptReloadHost.lastCompilation { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L210) | Gets the most recently completed compilation. | — | — | +| [`public bool Inno.Scripting.Reload.ScriptReloadHost.isUnloadVerificationPending { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L222) | Gets whether retired collectible assembly generations are still being verified for unload. | — | — | +| [`public bool Inno.Scripting.Reload.ScriptReloadHost.isFaulted { get; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L234) | Gets whether a retired generation exceeded the retention threshold and permanently stopped this host. | — | — | +| [`public void Inno.Scripting.Reload.ScriptReloadHost.Start()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L246) | Subscribes to committed asset changes and queues a cache-aware initial compilation request. | — | — | +| [`public bool Inno.Scripting.Reload.ScriptReloadHost.CancelCompilation(long operationId)`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L289) | Requests cancellation of the active compilation without changing the active script generation.
`operationId`: The observed request; a stale cancellation is rejected. | true when an active compilation received the request. | `System.ObjectDisposedException`: Thrown after the manager has been disposed. | +| [`public void Inno.Scripting.Reload.ScriptReloadHost.RecompileScripting()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L320) | Queues incremental recompilation of changed script assemblies. | — | `System.ObjectDisposedException`: Thrown after the manager has been disposed. | +| [`public void Inno.Scripting.Reload.ScriptReloadHost.ReloadScripting()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L332) | Queues a complete rebuild of both scripting load contexts while retaining the plugin generation. Valid cached artifacts are reused. | — | `System.ObjectDisposedException`: Thrown after the manager has been disposed. | +| [`public void Inno.Scripting.Reload.ScriptReloadHost.ReloadPlugins()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L341) | Queues replacement of the unified plugin generation and both dependent scripting generations. Valid script artifacts are reused when plugin reference fingerprints are unchanged. | — | `System.ObjectDisposedException`: Thrown after the manager has been disposed. | +| [`public bool Inno.Scripting.Reload.ScriptReloadHost.TryCompilePending(out System.Threading.Tasks.Task? compilation)`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L355) | Starts a pending compilation after the configured quiet period has elapsed.
`compilation`: The started compilation task, or null when none was ready. | true when a pending compilation was started. | — | +| [`public bool Inno.Scripting.Reload.ScriptReloadHost.ApplyPendingReload()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L516) | Applies the latest compiled generation, or commits a Plugin-unavailability generation when changed Plugin code cannot produce a replacement, at a caller-controlled main-thread safe point. | true when modules were replaced or retired; otherwise, false. | `System.ObjectDisposedException`: Thrown after the manager has been disposed. | +| [`public void Inno.Scripting.Reload.ScriptReloadHost.GenerateProjectFiles()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L583) | Generates standard SDK-style game/editor projects and a solution for IDE tooling. | — | `System.ObjectDisposedException`: Thrown after the manager has been disposed. | +| [`public void Inno.Scripting.Reload.ScriptReloadHost.Dispose()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L598) | Cancels and waits for active compilation work, stops Asset Database observation, and unloads the active script module. | — | — | +| [`public bool Inno.Scripting.Reload.ScriptReloadHost.AdvanceUnloadVerification(out System.Exception? failure)`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs#L675) | Advances cooperative unload verification for retired script generations.
`failure`: Receives the retention failure after all verification attempts, otherwise null. | true when no additional verification frame is required. | — | +| [`public sealed class Inno.Scripting.Reload.ScriptReloadOptions`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadOptions.cs#L7) | Configures automatic compilation requests and retired-generation verification. | — | — | +| [`public bool Inno.Scripting.Reload.ScriptReloadOptions.autoCompile { get; init; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadOptions.cs#L16) | Gets whether startup and subsequent source changes request automatic compilation. | — | — | | [`public int Inno.Scripting.Reload.ScriptReloadOptions.debounceMilliseconds { get; init; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadOptions.cs#L21) | Gets the quiet period applied to source changes before a compilation starts, in milliseconds. | — | — | +| [`public System.TimeSpan Inno.Scripting.Reload.ScriptReloadOptions.compilationWarningTimeout { get; init; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadOptions.cs#L30) | Gets the elapsed duration after which an active compilation is reported as long-running. | — | — | | [`public System.TimeSpan Inno.Scripting.Reload.ScriptReloadOptions.unloadCollectionInterval { get; init; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadOptions.cs#L35) | Gets the minimum interval between full garbage-collection attempts for retired assembly generations. | — | — | | [`public System.TimeSpan Inno.Scripting.Reload.ScriptReloadOptions.unloadRetentionTimeout { get; init; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadOptions.cs#L40) | Gets the duration after which a retained collectible generation permanently faults this reload host. | — | — | -| [`public sealed class Inno.Scripting.Reload.ScriptReloadOptions`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadOptions.cs#L7) | Configures automatic compilation requests and retired-generation verification. | — | — | +| [`public Inno.Scripting.Reload.ScriptReloadOptions.ScriptReloadOptions()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadOptions.cs#L7) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public sealed record Inno.Scripting.Reload.ScriptReloadProgress : System.IEquatable`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs#L21) | Atomically published progress owned by one reload request, containing no runtime or extension objects.
`operationId`: The host-local reload request sequence; zero precedes the first request.
`fraction`: The fraction through compilation, activation and verified retirement.
`stage`: The actual stage or terminal diagnostic.
`cancellationRequested`: Whether cancellation has been requested and still requires owned work to drain.
`canCancel`: Whether this exact operation currently admits cancellation. | — | — | +| [`public Inno.Scripting.Reload.ScriptReloadProgress.ScriptReloadProgress(long operationId, float fraction, string stage, bool cancellationRequested, bool canCancel = false)`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs#L21) | Atomically published progress owned by one reload request, containing no runtime or extension objects.
`operationId`: The host-local reload request sequence; zero precedes the first request.
`fraction`: The fraction through compilation, activation and verified retirement.
`stage`: The actual stage or terminal diagnostic.
`cancellationRequested`: Whether cancellation has been requested and still requires owned work to drain.
`canCancel`: Whether this exact operation currently admits cancellation. | — | — | +| [`public long Inno.Scripting.Reload.ScriptReloadProgress.operationId { get; init; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs#L22) | The host-local reload request sequence; zero precedes the first request. | — | — | +| [`public float Inno.Scripting.Reload.ScriptReloadProgress.fraction { get; init; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs#L23) | The fraction through compilation, activation and verified retirement. | — | — | +| [`public string Inno.Scripting.Reload.ScriptReloadProgress.stage { get; init; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs#L24) | The actual stage or terminal diagnostic. | — | — | +| [`public bool Inno.Scripting.Reload.ScriptReloadProgress.cancellationRequested { get; init; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs#L25) | Whether cancellation has been requested and still requires owned work to drain. | — | — | +| [`public bool Inno.Scripting.Reload.ScriptReloadProgress.canCancel { get; init; }`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs#L26) | Whether this exact operation currently admits cancellation. | — | — | +| [`public override string Inno.Scripting.Reload.ScriptReloadProgress.ToString()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs#L21) | Returns a string that represents the current object. | A string that represents the current object. | — | +| [`public static bool Inno.Scripting.Reload.ScriptReloadProgress.operator !=(Inno.Scripting.Reload.ScriptReloadProgress? left, Inno.Scripting.Reload.ScriptReloadProgress? right)`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs#L21) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public static bool Inno.Scripting.Reload.ScriptReloadProgress.operator ==(Inno.Scripting.Reload.ScriptReloadProgress? left, Inno.Scripting.Reload.ScriptReloadProgress? right)`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs#L21) | 由 C# 编译器生成的值契约成员。 | — | — | +| [`public override int Inno.Scripting.Reload.ScriptReloadProgress.GetHashCode()`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs#L21) | Serves as the default hash function. | A hash code for the current object. | — | +| [`public override bool Inno.Scripting.Reload.ScriptReloadProgress.Equals(object? obj)`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs#L21) | Determines whether the specified object is equal to the current object.
`obj`: The object to compare with the current object. | true if the specified object is equal to the current object; otherwise, false. | — | +| [`public bool Inno.Scripting.Reload.ScriptReloadProgress.Equals(Inno.Scripting.Reload.ScriptReloadProgress? other)`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs#L21) | Indicates whether the current object is equal to another object of the same type.
`other`: An object to compare with this object. | true if the current object is equal to the other parameter; otherwise, false. | — | +| [`public void Inno.Scripting.Reload.ScriptReloadProgress.Deconstruct(out long operationId, out float fraction, out string stage, out bool cancellationRequested, out bool canCancel)`](../../src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs#L21) | 由 C# 编译器生成的值契约成员。 | — | — | ## 项目依赖 diff --git a/records/architecture/acceptance/ISSUE58_DYNAMIC_MODAL_ACCEPTANCE.md b/records/architecture/acceptance/ISSUE58_DYNAMIC_MODAL_ACCEPTANCE.md new file mode 100644 index 00000000..c4b2e613 --- /dev/null +++ b/records/architecture/acceptance/ISSUE58_DYNAMIC_MODAL_ACCEPTANCE.md @@ -0,0 +1,142 @@ +# Issue #58:动态弹窗与局部 CI 验收 + +本报告覆盖 [#58](https://github.com/Wolfiora/InnoEngine/issues/58) 和直接关联的 [#59](https://github.com/Wolfiora/InnoEngine/issues/59)。SDK 为 10.0.402,目标为 .NET 10 / C# 14,BGCS 为 4.1.2。原始基线是 `dbae93e8f211d45a69cdffdb6afa3a33a0af0fa5`;该源码树与合并 PR #26 后的 master 相同。 + +当前状态:本地适用的功能、构建、原生回归、架构、Wiki、FlappyBird 工作流/退出与最终性能验收均已通过;远端 CI 尚待完成。Issue 保持 Open,不能在合并前关闭。 + +## 已确认原因与修复 + +旧 Renderer 的 `AlwaysAutoResize` 使用上一帧内容高度。实际原生基线轨迹证明,短文字变为五行时仍显示短窗口,随后收缩也会保留旧高度。它证明了切换帧错误;用户此前观察到的所有持续卡顿不能由这条轨迹一并解释。 + +当前链路是:工作流发布中立快照 → `OnPrepare` 捕获一次 → 按当前字体、宽度和尺度测量 → Renderer 决定本帧窗口边界 → 绘制一次 → 将携带操作身份的动作交回原 owner。 + +- Core 只增加中立的尺寸/准备契约,不引用 ImGui、导出或脚本实现。 +- Interactions 继续负责扩展异常隔离;缺少测量的自适应窗口明确失败,不回退上一帧内容尺寸。 +- ImGui 负责实际字体、边界、像素取整、换行和原生作用域;正宽度和零高度的部分尺寸声明得到保留。 +- Dialog Widget 统一消息、详情、进度、操作行与一个正文滚动区。正文过长时按钮仍在正文滚动区外;不添加补偿空行,不隐藏实际溢出。 +- Plugin Export 使用自身同一份字段声明测量和绘制;不把表单语义放进通用 Renderer。 +- Script Reload、Sample Import 和 Export 的状态权威仍在各自工作流 owner。快照包含操作身份,旧操作、取消后和退休后的更新不能覆盖当前状态。 +- Shader Check 的诊断发布和完成处理移至原 owner 的 Update,测量和绘制不执行编译或发布。 +- 脚本编译的 80% 明确表示等待激活、状态恢复和退休验证。Full GC、finalizer、弱 monitor、Faulted 和原子发布规则未放宽。 +- 未知总量显示活动状态,不显示虚假的 0%。Support Pack 的真实阶段采集仍由 #57 负责。 +- 活动指示只在工作仍持有资源时显示;失败或取消完成后的淡出不会把空进度重新标为 Working。取消请求仍等待实际工作退休。 + +## 实际文件与职责 + +```text +src/composition/editor/ +├── framework/ +│ ├── Inno.Editor.Core/Extensions/EditorModal.cs +│ └── Inno.Editor.Interactions/Runtime/EditorModalExtension.cs +├── features/ +│ ├── Inno.Editor.Assets/Samples/ +│ │ ├── AssetSampleImportModule.cs +│ │ └── AssetSampleImportProgress.cs +│ ├── Inno.Editor.Exporting/Runtime/ +│ │ ├── EditorExportService.cs +│ │ └── EditorExportProgress.cs +│ └── Inno.Editor.Scripting/Runtime/ +│ ├── IEditorScriptCompilation.cs +│ ├── EditorScripting.cs +│ └── EditorScriptCompilationProgress.cs +├── presentation/ +│ ├── Inno.Editor.ImGui/ +│ │ ├── Runtime/EditorModalRenderer.cs +│ │ ├── TextInput/ImGuiUtf8Buffer.cs +│ │ └── Widgets/ImGuiWidget.Dialog.cs +│ └── Inno.Editor.Workbench/ +│ ├── Exporting/{ExportWindowModule,GameExportProgressModal,PluginExportModal}.cs +│ └── Scripting/ScriptCompilationModal.cs +└── panels/ + ├── Inno.Editor.Panel.FileBrowser/Samples/AssetSampleImportModal.cs + └── Inno.Editor.Panel.ShaderEditor/ + ├── Documents/ShaderEditorDocuments.cs + └── Presentation/ShaderCheckModal.cs +src/runtime/scripting/Inno.Scripting.Reload/ +├── ScriptReloadHost.cs +└── ScriptReloadProgress.cs +tests/ +├── editor/Inno.Editor.ImGui.Tests/DynamicModalTests.cs +├── scripting/Inno.Editor.Scripting.Tests/ScriptingPipelineTests.Progress.cs +├── build/Inno.Build.Tests/BuildPipelineTests.ExportPresentation.cs +├── ci/{Select-ValidationScope,Test-ValidationScope,New-ValidationSolutionFilter}.ps1 +└── Invoke-EditorUiAcceptance.ps1 +.github/workflows/rendering-ci.yml +``` + +没有新增程序集、生产入口、事件总线、身份分配器、Modal 注册器或依赖解析器。`ImGuiUtf8Buffer` 复用原有文本桥接 owner;短文本使用调用内缓冲,长文本使用 BCL ArrayPool,并在 finally 清理归还,不保存原生借用。 + +测量缓存仅属于现有 UI Session 的 Widget,最多两项、每项合计 16,384 个字符,只保存字符串、标量和尺寸。键包含实际内容、可用尺寸、字体/baked 身份及实际布局参数;共享 atlas 和 remapped font 不使用该缓存。Session 退休清空缓存,不保存插件对象、Type、委托或原生地址。字体与 Zoom 切换具有原生回归。 + +## 构建与功能证据 + +本地原始证据 owner 为 `artifacts/acceptance/issue58/`。失败尝试保留独立名称,不覆盖为成功记录。 + +| 检查 | 结果与证据 | +| --- | --- | +| 正式 Editor Debug 构建 | 通过;`editor-verified.log/.binlog`,6m09s,0 warning / 0 error。随后两处私有实现调整通过 SDK Compile/Copy 更新真实调用方。 | +| 中立 Assets 引用闭包 | 通过;`assets-neutral-verified.log`,0 warning / 0 error。Compiler 已收回实现依赖,未保留无必要的公开接口。 | +| 原生动态 Modal、Widget、Viewport | 73 passed / 0 failed / 0 skipped;`dynamic-accepted.trx`。 | +| 动态尺度 | 28 个 Zoom×DPI 组合,覆盖 1280×720、1920×1080、640×480;为真实 ImGui Context 下的模拟显示指标,不冒充 28 台物理显示器。 | +| 输入、异常与生命周期 | 原生鼠标、Tab/Enter/Escape、取消、异常后下一帧、两个 Session、字体变化、100 次开关循环。见同一原生 TRX 的输出和几何记录。 | +| 脚本与 Sample | 七项独立进程回归通过:旧操作回调、编译失败、取消后的依赖保留、复制取消、Missing 激活、旧代退休、快照不保留 ALC。对应同名 TRX。 | +| Shader Check | 通过;`shader-verified.trx`,实际工作流、History 与文件选择不被绘制修改。 | +| 导出表单/状态/退休 | 5 passed / 0 failed / 0 skipped;`export-terminal.trx`,包含非合作 Support Pack 准备的严格退休。没有生成完整 Support Pack。 | +| 正式 IDE 投影 | Canvas、Rendering2D、FlappyBird 均通过;`projection-*.log`,未编辑生成文件。 | +| 架构、XML、脚本导出与 Wiki | 通过;`wiki-verified.log` 及目录,241/241 项目所有权求值、34,656 API entries、198 示例均无编译错误、0 未求值示例。其他平台产品编译单列未执行。 | +| CI 范围策略 | 20 项通过;`ci-contract-policy.log`。真实 Git 移动/删除、PR merge-base、混合/未知输入、手动 Full、过滤器空集、引用可见性及测试基础库契约证明。 | +| 验证项目过滤 | 从现有 Solution 派生 169 个实际生产项目和 13 个测试基础库/fixture 契约,不构建无关的可执行测试套件;MSBuild 仍解释引用闭包。没有第二套 resolver。 | +| CI 契约闭包复验 | `contract-proof/contracts.slnf` 正式 SourceDebug 构建通过,13 个基础库/fixture 均实际产出;`contract-proof/build.log/.binlog`,0 error。该次本地 NuGet 漏洞服务访问失败产生 26 项 NU1900 网络 warning,未屏蔽;不将其表述为零 warning 构建。 | + +## 产品、性能与限制 + +FlappyBird 使用独立复制的 Assets、Plugins 和项目设置,原 Samples 设置修改得到保护。第一次默认 30,000 帧验收在约 80 秒内完成八项工作流,但随后等待帧上限触发 600 秒 deadline,记录为失败,不能算正常退出通过。第二次 6,000 帧在约 36 秒正常退出,但冷脚本准备尚未完成,也记为失败。后续采用 15,000 帧及相同八项断言复验;不延长 timeout、不删除断言。帧数既不是脚本就绪条件,也不能代替功能断言。 + +性能在同一机器、SDK、Debug 配置、输入和原生闭包下比较。初始自动高度基线在长短交替时裁剪内容,不能把其较少的可见工作量当作性能优势。保留原始失败采样,并增加相同可见窗口面积的成对比较;动态切换正确性仍由实际自动高度 Renderer 测试验证,不通过固定窗口替代。 + +FlappyBird 最终 15,000 帧验收通过八项工作流,退出码 0,记录了 Editor state 冻结保存和 product resources released;证据为 `flappybird-accepted/`。前两次失败保留原结果,不计入通过。 + +最终采样为每个场景五组成对 AB/BA 独立进程、每次 1,000 帧预热及 100,000 次实际绘制;两边都断言真实 460×684 窗口及绘制次数。下面是五次中位数之比,不使用单次最好值。 + +| 场景 | CPU 变化 | P95 变化 | 托管分配变化 | +| --- | --- | --- | --- | +| 短消息 | +8.065% | +5.126% | −7.636% | +| 长消息 | +9.516% | +7.307% | −7.636% | +| 长短交替 | +7.372% | +2.733% | −7.636% | +| 滚动正文 | +1.581% | −1.945% | −2.182% | + +成对差值中位数也全部满足 CPU/P95 ≤10%:CPU 分别为 +6.349%、+7.439%、+4.821%、+7.115%;P95 为 +4.638%、+6.847%、−0.244%、+6.164%。不是零成本修复:当前帧测量/边界保证增加了少量 CPU,不能称作整体 CPU 加速。分配减少来自调用内 UTF-8 缓冲和复用布局;JIT 热路径注解不删除校验或改变 DEBUG 定义。两边 SDK 和配置相同,不归因为运行时升级。 + +环境为 Ryzen 9 6900HX / Windows 11 10.0.26200,拥有者进程固定最高可用逻辑 CPU;同一工作站同时使用中。证据是原生 UI CPU,不是整引擎 GPU/帧率结论。[完整原始数据及失败采样](ISSUE58_MODAL_PERFORMANCE.json)、[实际公开边界探针](ISSUE58_MODAL_PERFORMANCE_PROBE.cs.txt) 随报告保存。此前 `performance-equal` 的滚动 P95 +10.483% 明确作为失败保留,最终集在绘制热路径调整后重新完整采样。 + +复现时从基线提交恢复 ImGui 项目的全部手写源码,以标准 net10.0/C#14 审计工程生成原始同名程序集;以相同 supporting DLL 构建探针,候选探针额外定义 `CANDIDATE`。两者分别通过测试输出的 runtimeconfig/deps 运行 `dotnet exec ... ModalPerfProbe.dll `,按 AB/BA 顺序各五次。`DOTNET_TieredCompilation=0` 只设置于这两个探针进程。该临时审计工程不进入生产 Solution 或两个开发入口。 + +本轮未重做 Release、Player CoreCLR/NativeAOT、Browser、Support Pack、十次 Native 热构建和全仓无关测试。macOS 物理设备、不同物理显示器与人工视觉体验未执行。#56/#57、整体卡顿归因及其他独立 issue 不由本报告宣称解决。 + +## CI #59 + +范围由完整 Git diff 决定,包含删除与移动;PR 使用 merge-base,push 使用直接 before/head,无法确认的输入失败或进入 Full。纯 Editor 路径及其必要测试/文档可以选择 Editor;SDK、共享 build/runtime、平台、backend、未知变更选择 Full。只有可由实际 Git 差异证明未改变边的 Editor ProjectReference 可见性收紧允许局部验证,其余项目图变更仍 Full。 + +Editor CI 保留真实 Debug 产品、renderer smoke、普通及进程隔离的相关套件、当前架构/XML/Wiki;跳过 Release、NativeAOT 还原、十次热构建、无关全套测试和 Support Pack 生成。输出明确的选择原因及省略项;零测试和工具失败不能报成功。手动完整验收保留。冷 Native Debug 和全局 API/Wiki 仍有成本,尚未把未测量的加速倍数写成事实。 + +首轮远端 macOS 的 Editor 构建、Metal smoke、架构和相关套件均通过,但 Wiki 报告 18 项缺失编译引用:原先的生产项目过滤错误地遗漏了 Wiki 测试页所需的基础库及 fixture。该失败保留于 run `41125819779`,不能算作完整通过。过滤器现从 Solution 选择全部非 `IsTestProject` 契约,保留测试基础库并排除可执行测试套件;不放宽 Wiki 校验、不执行无关测试,也不增加基础库名单。最终远端结论由 PR 的对应 head 检查与 issue 证据记录。 + +## 十一项质量自查 + +以下评价只针对本次改动及真实调用链,不宣称整个引擎已达到没有缺陷的“现象级”。 + +| 维度 | 判断与证据 | 限制 / 后续改进 | +| --- | --- | --- | +| 架构 | Core 中立准备,Interactions 隔离,ImGui 测量,工作流拥有状态;架构验证通过。 | 其他领域问题仍按既有 issue 处理。 | +| 代码整洁度 | 共享 Widget 替代重复状态窗口布局;被替换读取 API 与调用方同步删除。 | 不据此证明全部历史文件排版一致。 | +| 代码干净程度 | 无 BGCS/vendor/generated 改动、无旧路径兼容、无双绘制和测试后门。 | 原始失败证据不被删改为成功。 | +| 抽象程度 | 公开边界只承载必要尺寸、呈现值和工作流快照;内部几何不扩大为通用布局框架。 | 后续新表单仍需由真实需求决定抽象。 | +| 可复用程度 | 编译、导出、Sample、Shader 共用 Dialog;Plugin 表单复用文本和尺寸机制。 | 不强迫领域表单使用消息窗的数据模型。 | +| 样式统一 | 同一字体、宽度、padding、spacing、像素取整和单一滚动 owner;尺度回归通过。 | 没有对全仓所有第三方 Drawer 做穷尽视觉审计;未来仍需规范和测试约束。 | +| 可拓展程度 | 扩展 override OnPrepare;不改 Renderer switch,不存跨代 callback。 | 自适应扩展必须实现当前测量契约,不能隐式依赖旧高度。 | +| 操作逻辑性 | 取消带操作身份;未知进度与确定进度区分,80% 子阶段明确说明。 | #57 尚需提供实际 Support Pack 阶段。 | +| Undo/Redo | 展示和测量不修改 History;Shader 完成回 owner Update;FlappyBird 包含手势与 Undo/Redo。 | 未重写也未重新验收所有无关 History 协议。 | +| 菜单清晰度 | 既有命令与 Modal ID 保持,未增加平行菜单入口。 | 本轮没有重新设计菜单信息架构。 | +| 组件颗粒度 | 无新增程序集;布局、会话、工作流各有 owner,现有基础能力得到复用。 | 不为将来可能的变化拆空项目或造新系统。 | + +最终代码完成 73 项完整原生回归;最后的绘制热路径注解后另有 12 项动态原生回归通过(`dynamic-hotpath.trx`)。远端 CI 必须在 PR head 上另行确认,不能拼接不同提交的远端成功结果。Issue 在分支验收后保持 Open,由完成验收的 PR 的 `Fixes` 在合并后关闭;不自动合并。Windows 不存在指定的 Glass.aiff,提示音未播放。 diff --git a/records/architecture/acceptance/ISSUE58_MODAL_PERFORMANCE.json b/records/architecture/acceptance/ISSUE58_MODAL_PERFORMANCE.json new file mode 100644 index 00000000..fc85deb3 --- /dev/null +++ b/records/architecture/acceptance/ISSUE58_MODAL_PERFORMANCE.json @@ -0,0 +1,380 @@ +{ + "baseRevision": "dbae93e8f211d45a69cdffdb6afa3a33a0af0fa5", + "sdk": "10.0.402", + "configuration": "Debug", + "environment": { + "cpu": { + "Name": "AMD Ryzen 9 6900HX with Radeon Graphics ", + "NumberOfCores": 8, + "NumberOfLogicalProcessors": 16 + }, + "os": { + "Caption": "Microsoft Windows 11 专业版", + "Version": "10.0.26200" + }, + "gpus": [ + { + "Name": "AMD Radeon(TM) Graphics", + "DriverVersion": "31.0.14084.6002" + }, + { + "Name": "NVIDIA GeForce RTX 3070 Ti Laptop GPU", + "DriverVersion": "32.0.15.9649" + } + ] + }, + "method": { + "repeats": 5, + "framesPerSample": 100000, + "warmupFrames": 1000, + "order": "AB, BA, AB, BA, AB", + "visibleWindow": [ + 460, + 684 + ], + "affinity": "Highest allowed logical CPU, owned probe processes only", + "tieredCompilation": "Disabled in both probe processes only", + "scope": "Native ImGui CPU and current-thread managed allocations; no GPU/whole-engine performance claim. The workstation was also in use. Both five-sample median ratios and paired median ratios are retained.", + "baseline": "Original full Inno.Editor.ImGui C# source at baseRevision rebuilt against the common supporting contract assemblies. Candidate uses measured dialog caller; this is not an old whole-engine binary comparison.", + "checks": [ + "Exactly one hundred thousand actual draws", + "Identical 460x684 visible window for timed work", + "Original auto-height transition trace recorded separately before timed fixed-extent work" + ] + }, + "summary": [ + { + "scenario": "short", + "cpuMilliseconds": { + "baseline": 5812.5, + "candidate": 6281.25, + "changePercent": 8.065, + "pairedMedianChangePercent": 6.349 + }, + "medianMicroseconds": { + "baseline": 52.2, + "candidate": 56.7, + "changePercent": 8.621, + "pairedMedianChangePercent": 8.621 + }, + "p95Microseconds": { + "baseline": 95.6, + "candidate": 100.5, + "changePercent": 5.126, + "pairedMedianChangePercent": 4.638 + }, + "allocatedBytesPerFrame": { + "baseline": 2200.00576, + "candidate": 2032.00576, + "changePercent": -7.636, + "pairedMedianChangePercent": -7.636 + } + }, + { + "scenario": "long", + "cpuMilliseconds": { + "baseline": 9031.25, + "candidate": 9890.625, + "changePercent": 9.516, + "pairedMedianChangePercent": 7.439 + }, + "medianMicroseconds": { + "baseline": 82.3, + "candidate": 88.8, + "changePercent": 7.898, + "pairedMedianChangePercent": 6.9 + }, + "p95Microseconds": { + "baseline": 161.5, + "candidate": 173.3, + "changePercent": 7.307, + "pairedMedianChangePercent": 6.847 + }, + "allocatedBytesPerFrame": { + "baseline": 2200.00576, + "candidate": 2032.00576, + "changePercent": -7.636, + "pairedMedianChangePercent": -7.636 + } + }, + { + "scenario": "alternating", + "cpuMilliseconds": { + "baseline": 8265.625, + "candidate": 8875, + "changePercent": 7.372, + "pairedMedianChangePercent": 4.821 + }, + "medianMicroseconds": { + "baseline": 77.4, + "candidate": 82.5, + "changePercent": 6.589, + "pairedMedianChangePercent": 6.589 + }, + "p95Microseconds": { + "baseline": 150, + "candidate": 154.1, + "changePercent": 2.733, + "pairedMedianChangePercent": -0.244 + }, + "allocatedBytesPerFrame": { + "baseline": 2200.00576, + "candidate": 2032.00576, + "changePercent": -7.636, + "pairedMedianChangePercent": -7.636 + } + }, + { + "scenario": "scroll", + "cpuMilliseconds": { + "baseline": 25703.125, + "candidate": 26109.375, + "changePercent": 1.581, + "pairedMedianChangePercent": 7.115 + }, + "medianMicroseconds": { + "baseline": 237, + "candidate": 246.1, + "changePercent": 3.84, + "pairedMedianChangePercent": 6.236 + }, + "p95Microseconds": { + "baseline": 426.8, + "candidate": 418.5, + "changePercent": -1.945, + "pairedMedianChangePercent": 6.164 + }, + "allocatedBytesPerFrame": { + "baseline": 2200.00576, + "candidate": 2152.00576, + "changePercent": -2.182, + "pairedMedianChangePercent": -2.182 + } + } + ], + "unacceptedSets": [ + "performance", + "performance-final", + "performance-verified", + "performance-equal" + ], + "unacceptedReason": "Earlier implementations, changing visible work, short/noisy samples, or a P95 threshold failure. Retained as raw unsuccessful evidence; never substituted for the final set.", + "baselineAssemblySha256": "57beb370f0041260616fe6d0657033d05230d18be3883d4ff06717a49a7cd06d", + "candidateAssemblySha256": "2393923f2c645b1d84dba43fb72903e448822d778bb3214301be97bd8149a186", + "baselineProbeSha256": "282c81879ac08d599fe30b3538a7a3e40a4eeb60701bf9e57e8fad5fe09b41df", + "candidateProbeSha256": "014ebf313263a651cd84fcb32b54d8314cc3829510d43985d99837ce834f6130", + "sets": { + "performance": { + "alternating-1-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":187.5,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":90.2,"p95Microseconds":169.8,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":108}, + "alternating-2-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":156.25,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":63.3,"p95Microseconds":131.4,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":108}, + "alternating-3-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":203.125,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":83.8,"p95Microseconds":173.9,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":108}, + "alternating-4-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":171.875,"allocatedBytesPerFrame":2200.288,"medianMicroseconds":76.4,"p95Microseconds":151.5,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":108}, + "alternating-5-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":171.875,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":65.4,"p95Microseconds":135.8,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":108}, + "diagnostic-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":171.875,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":63.1,"p95Microseconds":125.6,"preparations":0,"draws":2204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":20.18765,"windowWidth":460,"windowHeight":108}, + "long-1-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":250,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":111.6,"p95Microseconds":313.2,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":348}, + "long-2-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":234.375,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":104.5,"p95Microseconds":194.6,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":348}, + "long-3-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":250,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":98.6,"p95Microseconds":215.9,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":348}, + "long-4-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":265.625,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":105.6,"p95Microseconds":193.6,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":348}, + "long-5-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":187.5,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":86.5,"p95Microseconds":157.3,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":348}, + "scroll-1-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":531.25,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":240.6,"p95Microseconds":434.2,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":692}, + "scroll-2-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":687.5,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":295.6,"p95Microseconds":587.6,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":692}, + "scroll-3-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":562.5,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":246,"p95Microseconds":450.8,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":692}, + "scroll-4-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":687.5,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":306.4,"p95Microseconds":521.9,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":692}, + "scroll-5-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":578.125,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":256,"p95Microseconds":460,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":692}, + "short-1-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":140.625,"allocatedBytesPerFrame":2200.288,"medianMicroseconds":56.2,"p95Microseconds":115.7,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":108}, + "short-2-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":109.375,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":49.3,"p95Microseconds":94.5,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":108}, + "short-3-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":171.875,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":72.5,"p95Microseconds":151.8,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":108}, + "short-4-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":156.25,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":70.2,"p95Microseconds":181.4,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":108}, + "short-5-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":2000,"cpuMilliseconds":218.75,"allocatedBytesPerFrame":2200.556,"medianMicroseconds":80.3,"p95Microseconds":190.3,"preparations":0,"draws":2204,"windowWidth":460,"windowHeight":108}, + "alternating-1-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":250,"allocatedBytesPerFrame":2192.556,"medianMicroseconds":102.2,"p95Microseconds":202,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":344}, + "alternating-2-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":265.625,"allocatedBytesPerFrame":2192.556,"medianMicroseconds":125.3,"p95Microseconds":236.1,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":344}, + "alternating-3-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":343.75,"allocatedBytesPerFrame":2192.556,"medianMicroseconds":154.8,"p95Microseconds":303.2,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":344}, + "alternating-4-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":203.125,"allocatedBytesPerFrame":2192.556,"medianMicroseconds":83.8,"p95Microseconds":131.2,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":344}, + "alternating-5-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":234.375,"allocatedBytesPerFrame":2192.556,"medianMicroseconds":98,"p95Microseconds":205.7,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":344}, + "diagnostic-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":156.25,"allocatedBytesPerFrame":2032.556,"medianMicroseconds":69.4,"p95Microseconds":126.4,"preparations":2204,"draws":2204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":2.0650999999999997,"drawMicroseconds":21.5085,"windowWidth":460,"windowHeight":104}, + "long-1-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":281.25,"allocatedBytesPerFrame":2192.556,"medianMicroseconds":125.8,"p95Microseconds":220,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":344}, + "long-2-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":218.75,"allocatedBytesPerFrame":2192.556,"medianMicroseconds":103.7,"p95Microseconds":186.1,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":344}, + "long-3-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":250,"allocatedBytesPerFrame":2192.556,"medianMicroseconds":106.2,"p95Microseconds":197.5,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":344}, + "long-4-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":265.625,"allocatedBytesPerFrame":2192.556,"medianMicroseconds":108.5,"p95Microseconds":214,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":344}, + "long-5-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":375,"allocatedBytesPerFrame":2192.556,"medianMicroseconds":173.5,"p95Microseconds":311.2,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":344}, + "scroll-1-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":1203.125,"allocatedBytesPerFrame":2408.76,"medianMicroseconds":519.6,"p95Microseconds":978.4,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":684}, + "scroll-2-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":1046.875,"allocatedBytesPerFrame":2408.76,"medianMicroseconds":484.7,"p95Microseconds":840.6,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":684}, + "scroll-3-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":1296.875,"allocatedBytesPerFrame":2408.76,"medianMicroseconds":564.6,"p95Microseconds":1136,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":684}, + "scroll-4-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":1406.25,"allocatedBytesPerFrame":2408.76,"medianMicroseconds":643,"p95Microseconds":1113.4,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":684}, + "scroll-5-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":1109.375,"allocatedBytesPerFrame":2408.76,"medianMicroseconds":518.2,"p95Microseconds":898.5,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":684}, + "short-1-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":218.75,"allocatedBytesPerFrame":2192.556,"medianMicroseconds":119.1,"p95Microseconds":213,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":104}, + "short-2-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":234.375,"allocatedBytesPerFrame":2192.556,"medianMicroseconds":101.6,"p95Microseconds":174.1,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":104}, + "short-3-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":265.625,"allocatedBytesPerFrame":2192.556,"medianMicroseconds":116.7,"p95Microseconds":250.7,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":104}, + "short-4-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":171.875,"allocatedBytesPerFrame":2192.556,"medianMicroseconds":65.7,"p95Microseconds":150.1,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":104}, + "short-5-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":2000,"cpuMilliseconds":203.125,"allocatedBytesPerFrame":2192.556,"medianMicroseconds":91.1,"p95Microseconds":178.5,"preparations":2204,"draws":2204,"windowWidth":460,"windowHeight":104} + }, + "performance-final": { + "alternating-1-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":875,"allocatedBytesPerFrame":2200.1648,"medianMicroseconds":68.2,"p95Microseconds":207,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":34.88939,"windowWidth":460,"windowHeight":108}, + "alternating-2-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":828.125,"allocatedBytesPerFrame":2200.1648,"medianMicroseconds":65.8,"p95Microseconds":150.6,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":29.499059999999997,"windowWidth":460,"windowHeight":108}, + "alternating-3-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":578.125,"allocatedBytesPerFrame":2200.1648,"medianMicroseconds":64.1,"p95Microseconds":138.4,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":26.055250000000004,"windowWidth":460,"windowHeight":108}, + "alternating-4-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":796.875,"allocatedBytesPerFrame":2200.1112,"medianMicroseconds":73.7,"p95Microseconds":179.2,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":33.35265,"windowWidth":460,"windowHeight":108}, + "alternating-5-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":781.25,"allocatedBytesPerFrame":2200.1112,"medianMicroseconds":64.4,"p95Microseconds":140.7,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":27.20941,"windowWidth":460,"windowHeight":108}, + "long-1-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":1093.75,"allocatedBytesPerFrame":2200.1648,"medianMicroseconds":87.6,"p95Microseconds":237,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":62.17116,"windowWidth":460,"windowHeight":348}, + "long-2-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":1437.5,"allocatedBytesPerFrame":2200.1112,"medianMicroseconds":112.6,"p95Microseconds":330.8,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":83.6568,"windowWidth":460,"windowHeight":348}, + "long-3-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":1203.125,"allocatedBytesPerFrame":2200.1112,"medianMicroseconds":98.3,"p95Microseconds":298.6,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":67.03325,"windowWidth":460,"windowHeight":348}, + "long-4-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":1000,"allocatedBytesPerFrame":2200.1112,"medianMicroseconds":90.4,"p95Microseconds":230.7,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":74.05488000000001,"windowWidth":460,"windowHeight":348}, + "long-5-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":1171.875,"allocatedBytesPerFrame":2200.1648,"medianMicroseconds":92.1,"p95Microseconds":271.7,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":59.024719999999995,"windowWidth":460,"windowHeight":348}, + "scroll-1-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":2843.75,"allocatedBytesPerFrame":2200.1648,"medianMicroseconds":243,"p95Microseconds":571.1,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":251.47231000000002,"windowWidth":460,"windowHeight":692}, + "scroll-2-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":2828.125,"allocatedBytesPerFrame":2200.1112,"medianMicroseconds":244.8,"p95Microseconds":558.8,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":239.61993999999999,"windowWidth":460,"windowHeight":692}, + "scroll-3-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":2640.625,"allocatedBytesPerFrame":2200.1112,"medianMicroseconds":236.2,"p95Microseconds":533.6,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":238.95164000000003,"windowWidth":460,"windowHeight":692}, + "scroll-4-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":2343.75,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":258,"p95Microseconds":620.3,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":262.54514000000006,"windowWidth":460,"windowHeight":692}, + "scroll-5-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":2578.125,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":234.4,"p95Microseconds":500.1,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":216.76715999999996,"windowWidth":460,"windowHeight":692}, + "short-1-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":703.125,"allocatedBytesPerFrame":2200.1648,"medianMicroseconds":58.4,"p95Microseconds":138.8,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":20.975479999999997,"windowWidth":460,"windowHeight":108}, + "short-2-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":703.125,"allocatedBytesPerFrame":2200.1648,"medianMicroseconds":53.7,"p95Microseconds":126,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":20.14121,"windowWidth":460,"windowHeight":108}, + "short-3-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":671.875,"allocatedBytesPerFrame":2200.1648,"medianMicroseconds":57.3,"p95Microseconds":132,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":22.97728,"windowWidth":460,"windowHeight":108}, + "short-4-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":562.5,"allocatedBytesPerFrame":2200.1648,"medianMicroseconds":60,"p95Microseconds":145.1,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":22.074920000000002,"windowWidth":460,"windowHeight":108}, + "short-5-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":578.125,"allocatedBytesPerFrame":2200.1648,"medianMicroseconds":63.5,"p95Microseconds":156.5,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":27.1387,"windowWidth":460,"windowHeight":108}, + "alternating-1-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":906.25,"allocatedBytesPerFrame":2032.1648,"medianMicroseconds":80,"p95Microseconds":169,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":1.94303,"drawMicroseconds":36.23599,"windowWidth":460,"windowHeight":344}, + "alternating-2-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":1000,"allocatedBytesPerFrame":2032.1112,"medianMicroseconds":84.7,"p95Microseconds":201.7,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":2.6675600000000004,"drawMicroseconds":41.288059999999994,"windowWidth":460,"windowHeight":344}, + "alternating-3-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":843.75,"allocatedBytesPerFrame":2032.1648,"medianMicroseconds":88.5,"p95Microseconds":244.8,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":3.1028300000000004,"drawMicroseconds":44.82415,"windowWidth":460,"windowHeight":344}, + "alternating-4-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":703.125,"allocatedBytesPerFrame":2032.1648,"medianMicroseconds":83.3,"p95Microseconds":206,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":2.09138,"drawMicroseconds":39.46504,"windowWidth":460,"windowHeight":344}, + "alternating-5-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":1062.5,"allocatedBytesPerFrame":2032.1648,"medianMicroseconds":86.9,"p95Microseconds":255.3,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":3.0497199999999998,"drawMicroseconds":45.287119999999994,"windowWidth":460,"windowHeight":344}, + "long-1-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":1109.375,"allocatedBytesPerFrame":2032.1648,"medianMicroseconds":93,"p95Microseconds":221.7,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.09819,"drawMicroseconds":56.289880000000004,"windowWidth":460,"windowHeight":344}, + "long-2-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":1218.75,"allocatedBytesPerFrame":2032.1648,"medianMicroseconds":92.6,"p95Microseconds":254.5,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.30887,"drawMicroseconds":62.48236,"windowWidth":460,"windowHeight":344}, + "long-3-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":1265.625,"allocatedBytesPerFrame":2032.0576,"medianMicroseconds":96,"p95Microseconds":293.6,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.81533,"drawMicroseconds":72.37532,"windowWidth":460,"windowHeight":344}, + "long-4-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":1140.625,"allocatedBytesPerFrame":2032.1112,"medianMicroseconds":94.8,"p95Microseconds":231.3,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.29451,"drawMicroseconds":70.699,"windowWidth":460,"windowHeight":344}, + "long-5-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":1312.5,"allocatedBytesPerFrame":2032.1648,"medianMicroseconds":110.1,"p95Microseconds":390.3,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":3.2804800000000003,"drawMicroseconds":74.98432000000001,"windowWidth":460,"windowHeight":344}, + "scroll-1-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":2921.875,"allocatedBytesPerFrame":2152.1648,"medianMicroseconds":252.2,"p95Microseconds":551.3,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":4.85265,"drawMicroseconds":256.54868,"windowWidth":460,"windowHeight":684}, + "scroll-2-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":3109.375,"allocatedBytesPerFrame":2153.8056,"medianMicroseconds":261.7,"p95Microseconds":594.2,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":3.88286,"drawMicroseconds":247.8817,"windowWidth":460,"windowHeight":684}, + "scroll-3-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":2843.75,"allocatedBytesPerFrame":2152.0576,"medianMicroseconds":244.7,"p95Microseconds":525.5,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":3.0324899999999997,"drawMicroseconds":238.34735,"windowWidth":460,"windowHeight":684}, + "scroll-4-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":2562.5,"allocatedBytesPerFrame":2152.0576,"medianMicroseconds":250.2,"p95Microseconds":543.2,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":3.11846,"drawMicroseconds":237.29708000000002,"windowWidth":460,"windowHeight":684}, + "scroll-5-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":2906.25,"allocatedBytesPerFrame":2152.0576,"medianMicroseconds":254.5,"p95Microseconds":560.4,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":3.07755,"drawMicroseconds":241.95665,"windowWidth":460,"windowHeight":684}, + "short-1-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":890.625,"allocatedBytesPerFrame":2032.1648,"medianMicroseconds":69.7,"p95Microseconds":201.6,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":2.7659199999999995,"drawMicroseconds":28.72798,"windowWidth":460,"windowHeight":104}, + "short-2-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":875,"allocatedBytesPerFrame":2032.1648,"medianMicroseconds":69,"p95Microseconds":181.7,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":2.56593,"drawMicroseconds":29.394779999999997,"windowWidth":460,"windowHeight":104}, + "short-3-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":906.25,"allocatedBytesPerFrame":2032.1112,"medianMicroseconds":66,"p95Microseconds":216.9,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":3.0937200000000002,"drawMicroseconds":34.12413000000001,"windowWidth":460,"windowHeight":104}, + "short-4-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":859.375,"allocatedBytesPerFrame":2032.1648,"medianMicroseconds":65.5,"p95Microseconds":188.1,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":2.20437,"drawMicroseconds":27.265620000000002,"windowWidth":460,"windowHeight":104}, + "short-5-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":781.25,"allocatedBytesPerFrame":2032.1648,"medianMicroseconds":70.8,"p95Microseconds":215.3,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":3.1364099999999997,"drawMicroseconds":28.259320000000002,"windowWidth":460,"windowHeight":104} + }, + "performance-verified": { + "alternating-1-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":843.75,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":64.7,"p95Microseconds":156.3,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":31.88533,"windowWidth":460,"windowHeight":108}, + "alternating-2-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":734.375,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":62.1,"p95Microseconds":133.7,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":26.656609999999997,"windowWidth":460,"windowHeight":108}, + "alternating-3-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":765.625,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":63.8,"p95Microseconds":192.8,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":28.020970000000002,"windowWidth":460,"windowHeight":108}, + "alternating-4-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":1109.375,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":92,"p95Microseconds":348.2,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":54.58896,"windowWidth":460,"windowHeight":108}, + "alternating-5-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":1109.375,"allocatedBytesPerFrame":2200.1112,"medianMicroseconds":72.1,"p95Microseconds":383.1,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":71.5647,"windowWidth":460,"windowHeight":108}, + "long-1-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":843.75,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":79.3,"p95Microseconds":165.1,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":46.26648,"windowWidth":460,"windowHeight":348}, + "long-2-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":875,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":76.9,"p95Microseconds":144.8,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":44.354690000000005,"windowWidth":460,"windowHeight":348}, + "long-3-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":1000,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":83.1,"p95Microseconds":192.2,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":49.24053,"windowWidth":460,"windowHeight":348}, + "long-4-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":671.875,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":78,"p95Microseconds":152.2,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":46.17931,"windowWidth":460,"windowHeight":348}, + "long-5-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":906.25,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":89,"p95Microseconds":294.3,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":65.42820999999999,"windowWidth":460,"windowHeight":348}, + "scroll-1-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":2687.5,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":228.1,"p95Microseconds":582.6,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":219.42995,"windowWidth":460,"windowHeight":692}, + "scroll-2-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":2421.875,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":242.7,"p95Microseconds":633.2,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":254.24846000000002,"windowWidth":460,"windowHeight":692}, + "scroll-3-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":2984.375,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":256.3,"p95Microseconds":693.9,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":276.5503,"windowWidth":460,"windowHeight":692}, + "scroll-4-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":2312.5,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":205.4,"p95Microseconds":364.6,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":179.88412,"windowWidth":460,"windowHeight":692}, + "scroll-5-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":2343.75,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":211.5,"p95Microseconds":421.8,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":197.40594,"windowWidth":460,"windowHeight":692}, + "short-1-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":656.25,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":52.6,"p95Microseconds":129.8,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":23.84601,"windowWidth":460,"windowHeight":108}, + "short-2-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":578.125,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":50.9,"p95Microseconds":96.8,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":16.614060000000002,"windowWidth":460,"windowHeight":108}, + "short-3-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":593.75,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":49.9,"p95Microseconds":94.9,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":16.15597,"windowWidth":460,"windowHeight":108}, + "short-4-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":578.125,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":49.2,"p95Microseconds":116.2,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":18.20866,"windowWidth":460,"windowHeight":108}, + "short-5-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":10000,"cpuMilliseconds":625,"allocatedBytesPerFrame":2200.0576,"medianMicroseconds":52.2,"p95Microseconds":120.3,"preparations":0,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":17.98041,"windowWidth":460,"windowHeight":108}, + "alternating-1-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":1250,"allocatedBytesPerFrame":2032.0576,"medianMicroseconds":103.6,"p95Microseconds":400.4,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":4.02863,"drawMicroseconds":66.59193,"windowWidth":460,"windowHeight":344}, + "alternating-2-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":890.625,"allocatedBytesPerFrame":2032.0576,"medianMicroseconds":81.3,"p95Microseconds":190.9,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":2.12526,"drawMicroseconds":35.673809999999996,"windowWidth":460,"windowHeight":344}, + "alternating-3-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":1140.625,"allocatedBytesPerFrame":2032.0576,"medianMicroseconds":87.1,"p95Microseconds":267.5,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":3.0299400000000003,"drawMicroseconds":49.58897,"windowWidth":460,"windowHeight":344}, + "alternating-4-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":1109.375,"allocatedBytesPerFrame":2032.0576,"medianMicroseconds":91.2,"p95Microseconds":365.1,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":3.3892300000000004,"drawMicroseconds":52.44722000000001,"windowWidth":460,"windowHeight":344}, + "alternating-5-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":828.125,"allocatedBytesPerFrame":2032.1112,"medianMicroseconds":75.5,"p95Microseconds":185,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":2.0372399999999997,"drawMicroseconds":37.07888,"windowWidth":460,"windowHeight":344}, + "long-1-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":1015.625,"allocatedBytesPerFrame":2032.0576,"medianMicroseconds":85.6,"p95Microseconds":185.8,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":1.9416800000000003,"drawMicroseconds":47.7466,"windowWidth":460,"windowHeight":344}, + "long-2-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":1015.625,"allocatedBytesPerFrame":2032.0576,"medianMicroseconds":89.2,"p95Microseconds":177.8,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":1.8142100000000003,"drawMicroseconds":51.237089999999995,"windowWidth":460,"windowHeight":344}, + "long-3-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":1281.25,"allocatedBytesPerFrame":2032.0576,"medianMicroseconds":107.5,"p95Microseconds":374.4,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":3.23012,"drawMicroseconds":68.22700999999999,"windowWidth":460,"windowHeight":344}, + "long-4-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":1062.5,"allocatedBytesPerFrame":2032.0576,"medianMicroseconds":98.4,"p95Microseconds":302.8,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":3.71765,"drawMicroseconds":57.83623000000001,"windowWidth":460,"windowHeight":344}, + "long-5-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":890.625,"allocatedBytesPerFrame":2032.0576,"medianMicroseconds":84.3,"p95Microseconds":169.1,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":1.84912,"drawMicroseconds":45.939679999999996,"windowWidth":460,"windowHeight":344}, + "scroll-1-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":2562.5,"allocatedBytesPerFrame":2152.0576,"medianMicroseconds":225.9,"p95Microseconds":453.2,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.53572,"drawMicroseconds":208.91664,"windowWidth":460,"windowHeight":684}, + "scroll-2-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":2046.875,"allocatedBytesPerFrame":2152.0576,"medianMicroseconds":237,"p95Microseconds":448.1,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.5407900000000003,"drawMicroseconds":204.12977,"windowWidth":460,"windowHeight":684}, + "scroll-3-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":3187.5,"allocatedBytesPerFrame":2152.0576,"medianMicroseconds":286.6,"p95Microseconds":725.4,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":3.85204,"drawMicroseconds":271.98012,"windowWidth":460,"windowHeight":684}, + "scroll-4-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":2500,"allocatedBytesPerFrame":2152.0576,"medianMicroseconds":226.9,"p95Microseconds":416.9,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.37663,"drawMicroseconds":195.18863000000002,"windowWidth":460,"windowHeight":684}, + "scroll-5-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":2515.625,"allocatedBytesPerFrame":2152.0576,"medianMicroseconds":225.7,"p95Microseconds":411.1,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.34032,"drawMicroseconds":192.43509,"windowWidth":460,"windowHeight":684}, + "short-1-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":625,"allocatedBytesPerFrame":2032.0576,"medianMicroseconds":55.6,"p95Microseconds":107.6,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":1.5796700000000001,"drawMicroseconds":16.70863,"windowWidth":460,"windowHeight":104}, + "short-2-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":593.75,"allocatedBytesPerFrame":2032.0576,"medianMicroseconds":53.6,"p95Microseconds":99.7,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":1.67462,"drawMicroseconds":15.76755,"windowWidth":460,"windowHeight":104}, + "short-3-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":875,"allocatedBytesPerFrame":2032.0576,"medianMicroseconds":64,"p95Microseconds":197.6,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":2.62845,"drawMicroseconds":23.42892,"windowWidth":460,"windowHeight":104}, + "short-4-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":671.875,"allocatedBytesPerFrame":2032.0576,"medianMicroseconds":55.8,"p95Microseconds":106,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":1.62,"drawMicroseconds":16.36219,"windowWidth":460,"windowHeight":104}, + "short-5-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":10000,"cpuMilliseconds":656.25,"allocatedBytesPerFrame":2032.0576,"medianMicroseconds":56.1,"p95Microseconds":117.8,"preparations":10204,"draws":10204,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":1.97668,"drawMicroseconds":18.75872,"windowWidth":460,"windowHeight":104} + }, + "performance-equal": { + "alternating-1-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":6671.875,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":68.1,"p95Microseconds":93.5,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":28.600816000000002,"windowWidth":460,"windowHeight":684}, + "alternating-2-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":6687.5,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":68.1,"p95Microseconds":94.3,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":28.633522999999997,"windowWidth":460,"windowHeight":684}, + "alternating-3-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":6859.375,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":68.7,"p95Microseconds":103.8,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":29.863742000000002,"windowWidth":460,"windowHeight":684}, + "alternating-4-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":7062.5,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":69.6,"p95Microseconds":113.6,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":30.769172,"windowWidth":460,"windowHeight":684}, + "alternating-5-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":7250,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":69.8,"p95Microseconds":112.3,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":30.634113,"windowWidth":460,"windowHeight":684}, + "long-1-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":9328.125,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":84.9,"p95Microseconds":148,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":47.6809,"windowWidth":460,"windowHeight":684}, + "long-2-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":9140.625,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":83.7,"p95Microseconds":147.2,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":46.886457,"windowWidth":460,"windowHeight":684}, + "long-3-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":9156.25,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":84.2,"p95Microseconds":143,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":47.101380999999996,"windowWidth":460,"windowHeight":684}, + "long-4-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":9984.375,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":89.1,"p95Microseconds":165.9,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":50.501955,"windowWidth":460,"windowHeight":684}, + "long-5-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":10187.5,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":91.5,"p95Microseconds":165.5,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":50.701141,"windowWidth":460,"windowHeight":684}, + "scroll-1-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":21984.375,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":208,"p95Microseconds":302.4,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":174.076509,"windowWidth":460,"windowHeight":684}, + "scroll-2-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":22656.25,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":215,"p95Microseconds":335.2,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":178.11321,"windowWidth":460,"windowHeight":684}, + "scroll-3-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":24062.5,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":225,"p95Microseconds":379.6,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":186.324084,"windowWidth":460,"windowHeight":684}, + "scroll-4-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":21656.25,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":207.8,"p95Microseconds":285.6,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":171.854263,"windowWidth":460,"windowHeight":684}, + "scroll-5-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":21593.75,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":206.6,"p95Microseconds":280.8,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":171.69035900000003,"windowWidth":460,"windowHeight":684}, + "short-1-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":6281.25,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":55.8,"p95Microseconds":104.6,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":18.209364,"windowWidth":460,"windowHeight":684}, + "short-2-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":5859.375,"allocatedBytesPerFrame":2200.01112,"medianMicroseconds":53.6,"p95Microseconds":92,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":17.211305999999997,"windowWidth":460,"windowHeight":684}, + "short-3-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":5968.75,"allocatedBytesPerFrame":2200.01112,"medianMicroseconds":53.4,"p95Microseconds":95.5,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":17.04205,"windowWidth":460,"windowHeight":684}, + "short-4-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":6093.75,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":54,"p95Microseconds":103.2,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":17.683357,"windowWidth":460,"windowHeight":684}, + "short-5-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":5984.375,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":54.7,"p95Microseconds":98.8,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":17.996686999999998,"windowWidth":460,"windowHeight":684}, + "alternating-1-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":7421.875,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":72.6,"p95Microseconds":119.6,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":1.993485,"drawMicroseconds":30.100088,"windowWidth":460,"windowHeight":684}, + "alternating-2-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":7281.25,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":73.3,"p95Microseconds":103.6,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":1.744334,"drawMicroseconds":28.807613999999997,"windowWidth":460,"windowHeight":684}, + "alternating-3-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":7156.25,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":72.4,"p95Microseconds":100.9,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":1.61978,"drawMicroseconds":28.319247,"windowWidth":460,"windowHeight":684}, + "alternating-4-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":7343.75,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":73.2,"p95Microseconds":109.6,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":1.577238,"drawMicroseconds":29.215718000000003,"windowWidth":460,"windowHeight":684}, + "alternating-5-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":7328.125,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":72.5,"p95Microseconds":107.8,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":1.583134,"drawMicroseconds":28.978272,"windowWidth":460,"windowHeight":684}, + "long-1-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":9828.125,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":89.9,"p95Microseconds":160.2,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.034484,"drawMicroseconds":47.53551100000001,"windowWidth":460,"windowHeight":684}, + "long-2-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":9765.625,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":90,"p95Microseconds":154.1,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":1.9815310000000002,"drawMicroseconds":47.49286,"windowWidth":460,"windowHeight":684}, + "long-3-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":9515.625,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":88.3,"p95Microseconds":145.8,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":1.824215,"drawMicroseconds":45.697837,"windowWidth":460,"windowHeight":684}, + "long-4-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":10828.125,"allocatedBytesPerFrame":2032.01112,"medianMicroseconds":94.4,"p95Microseconds":187.6,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.1966740000000002,"drawMicroseconds":51.747812,"windowWidth":460,"windowHeight":684}, + "long-5-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":9718.75,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":90.1,"p95Microseconds":160.8,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.012983,"drawMicroseconds":47.280532,"windowWidth":460,"windowHeight":684}, + "scroll-1-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":23328.125,"allocatedBytesPerFrame":2152.00576,"medianMicroseconds":220.1,"p95Microseconds":350.7,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.089535,"drawMicroseconds":184.890683,"windowWidth":460,"windowHeight":684}, + "scroll-2-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":23203.125,"allocatedBytesPerFrame":2152.00576,"medianMicroseconds":219.3,"p95Microseconds":307.7,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.051532,"drawMicroseconds":181.073673,"windowWidth":460,"windowHeight":684}, + "scroll-3-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":24484.375,"allocatedBytesPerFrame":2152.00576,"medianMicroseconds":233.2,"p95Microseconds":362.2,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.350194,"drawMicroseconds":190.02865400000002,"windowWidth":460,"windowHeight":684}, + "scroll-4-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":23843.75,"allocatedBytesPerFrame":2152.00576,"medianMicroseconds":226,"p95Microseconds":334.1,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.118251,"drawMicroseconds":186.98395900000003,"windowWidth":460,"windowHeight":684}, + "scroll-5-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":23156.25,"allocatedBytesPerFrame":2152.00576,"medianMicroseconds":221.2,"p95Microseconds":302.5,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.128444,"drawMicroseconds":180.544113,"windowWidth":460,"windowHeight":684}, + "short-1-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":6546.875,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":59.3,"p95Microseconds":113.1,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":1.83436,"drawMicroseconds":17.227926,"windowWidth":460,"windowHeight":684}, + "short-2-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":6453.125,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":59.4,"p95Microseconds":105.9,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":1.730505,"drawMicroseconds":16.857964000000003,"windowWidth":460,"windowHeight":684}, + "short-3-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":6562.5,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":59.3,"p95Microseconds":103.3,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":1.787124,"drawMicroseconds":16.793112,"windowWidth":460,"windowHeight":684}, + "short-4-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":6921.875,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":61.2,"p95Microseconds":118.7,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":1.9289680000000002,"drawMicroseconds":18.87197,"windowWidth":460,"windowHeight":684}, + "short-5-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":6250,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":58.9,"p95Microseconds":98.7,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":1.82051,"drawMicroseconds":16.322425,"windowWidth":460,"windowHeight":684} + }, + "performance-accepted": { + "alternating-1-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":8265.625,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":77.4,"p95Microseconds":150,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":36.915656,"windowWidth":460,"windowHeight":684}, + "alternating-2-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":7812.5,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":75.6,"p95Microseconds":133.6,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":33.7591,"windowWidth":460,"windowHeight":684}, + "alternating-3-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":8796.875,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":79.1,"p95Microseconds":163.8,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":38.069027999999996,"windowWidth":460,"windowHeight":684}, + "alternating-4-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":8750,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":80.3,"p95Microseconds":158,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":37.048637,"windowWidth":460,"windowHeight":684}, + "alternating-5-baseline.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":7687.5,"allocatedBytesPerFrame":2200.01112,"medianMicroseconds":73.9,"p95Microseconds":129.7,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":0,"drawMicroseconds":32.87891,"windowWidth":460,"windowHeight":684}, + "long-1-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":9031.25,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":80.5,"p95Microseconds":161.5,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":48.78577800000001,"windowWidth":460,"windowHeight":684}, + "long-2-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":9031.25,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":82.3,"p95Microseconds":156,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":49.197883999999995,"windowWidth":460,"windowHeight":684}, + "long-3-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":8812.5,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":81.5,"p95Microseconds":150.1,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":47.124932,"windowWidth":460,"windowHeight":684}, + "long-4-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":10093.75,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":88.4,"p95Microseconds":173.8,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":51.379408,"windowWidth":460,"windowHeight":684}, + "long-5-baseline.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":10031.25,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":89.1,"p95Microseconds":171.7,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":51.251152999999995,"windowWidth":460,"windowHeight":684}, + "scroll-1-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":28609.375,"allocatedBytesPerFrame":2200.01112,"medianMicroseconds":253.8,"p95Microseconds":500.1,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":228.855887,"windowWidth":460,"windowHeight":684}, + "scroll-2-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":25750,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":238.2,"p95Microseconds":426.8,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":199.72491399999998,"windowWidth":460,"windowHeight":684}, + "scroll-3-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":24375,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":230.9,"p95Microseconds":394.2,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":192.90023,"windowWidth":460,"windowHeight":684}, + "scroll-4-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":25703.125,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":237,"p95Microseconds":432.3,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":202.01332,"windowWidth":460,"windowHeight":684}, + "scroll-5-baseline.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":23578.125,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":218.6,"p95Microseconds":407.9,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":0,"drawMicroseconds":187.278075,"windowWidth":460,"windowHeight":684}, + "short-1-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":5531.25,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":50.8,"p95Microseconds":85.5,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":16.02667,"windowWidth":460,"windowHeight":684}, + "short-2-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":5625,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":52.1,"p95Microseconds":88.8,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":16.692658,"windowWidth":460,"windowHeight":684}, + "short-3-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":5812.5,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":52.2,"p95Microseconds":95.6,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":16.515031999999998,"windowWidth":460,"windowHeight":684}, + "short-4-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":6046.875,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":53.6,"p95Microseconds":103.5,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":18.121526,"windowWidth":460,"windowHeight":684}, + "short-5-baseline.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":36,"actionBottom":161,"windowBottom":96},{"messageLength":5,"windowWidth":460,"windowHeight":108,"actionBottom":418,"windowBottom":425},{"messageLength":31,"windowWidth":460,"windowHeight":108,"actionBottom":482,"windowBottom":425},{"messageLength":5,"windowWidth":460,"windowHeight":172,"actionBottom":386,"windowBottom":457}],"frames":100000,"cpuMilliseconds":5906.25,"allocatedBytesPerFrame":2200.00576,"medianMicroseconds":52.2,"p95Microseconds":97.8,"preparations":0,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":0,"drawMicroseconds":17.352038,"windowWidth":460,"windowHeight":684}, + "alternating-1-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":8875,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":82.5,"p95Microseconds":148.7,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":1.915913,"drawMicroseconds":34.814951,"windowWidth":460,"windowHeight":684}, + "alternating-2-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":8046.875,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":77.9,"p95Microseconds":132.2,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":1.8210229999999998,"drawMicroseconds":31.779812999999997,"windowWidth":460,"windowHeight":684}, + "alternating-3-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":8984.375,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":83.7,"p95Microseconds":163.4,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":2.0926489999999998,"drawMicroseconds":36.323358,"windowWidth":460,"windowHeight":684}, + "alternating-4-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":9171.875,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":86.3,"p95Microseconds":169.2,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":2.2787119999999996,"drawMicroseconds":35.902166,"windowWidth":460,"windowHeight":684}, + "alternating-5-candidate.json": {"scenario":"alternating","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":8703.125,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":79.1,"p95Microseconds":154.1,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=35; size=16","prepMicroseconds":1.8462590000000003,"drawMicroseconds":33.640596,"windowWidth":460,"windowHeight":684}, + "long-1-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":9875,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":88.8,"p95Microseconds":171.7,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":1.9392709999999997,"drawMicroseconds":48.885671,"windowWidth":460,"windowHeight":684}, + "long-2-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":9703.125,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":87.5,"p95Microseconds":167.4,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":1.941763,"drawMicroseconds":47.144963999999995,"windowWidth":460,"windowHeight":684}, + "long-3-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":9890.625,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":88.2,"p95Microseconds":173.3,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":1.920423,"drawMicroseconds":47.711426,"windowWidth":460,"windowHeight":684}, + "long-4-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":10531.25,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":94.5,"p95Microseconds":185.7,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.3207560000000003,"drawMicroseconds":53.554393,"windowWidth":460,"windowHeight":684}, + "long-5-candidate.json": {"scenario":"long","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":10312.5,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":92.6,"p95Microseconds":179.3,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.0201320000000003,"drawMicroseconds":49.289,"windowWidth":460,"windowHeight":684}, + "scroll-1-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":32953.125,"allocatedBytesPerFrame":2152.1752,"medianMicroseconds":290.5,"p95Microseconds":544.2,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":3.831637,"drawMicroseconds":263.65045299999997,"windowWidth":460,"windowHeight":684}, + "scroll-2-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":30515.625,"allocatedBytesPerFrame":2152.01112,"medianMicroseconds":278.3,"p95Microseconds":519.7,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":3.506331,"drawMicroseconds":240.37366299999996,"windowWidth":460,"windowHeight":684}, + "scroll-3-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":26109.375,"allocatedBytesPerFrame":2152.00576,"medianMicroseconds":245.3,"p95Microseconds":418.5,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.7331209999999997,"drawMicroseconds":202.901828,"windowWidth":460,"windowHeight":684}, + "scroll-4-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":25921.875,"allocatedBytesPerFrame":2152.00576,"medianMicroseconds":246.1,"p95Microseconds":416.1,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.628089,"drawMicroseconds":204.75945,"windowWidth":460,"windowHeight":684}, + "scroll-5-candidate.json": {"scenario":"scroll","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":23953.125,"allocatedBytesPerFrame":2152.00576,"medianMicroseconds":226.5,"p95Microseconds":383.3,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=34; size=16","prepMicroseconds":2.287407,"drawMicroseconds":189.78212200000004,"windowWidth":460,"windowHeight":684}, + "short-1-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":5953.125,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":55.5,"p95Microseconds":96.9,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":1.594428,"drawMicroseconds":15.77046,"windowWidth":460,"windowHeight":684}, + "short-2-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":5890.625,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":55.6,"p95Microseconds":89.9,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":1.646115,"drawMicroseconds":15.439063999999998,"windowWidth":460,"windowHeight":684}, + "short-3-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":6578.125,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":58.1,"p95Microseconds":114.2,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":1.9381979999999999,"drawMicroseconds":16.907339,"windowWidth":460,"windowHeight":684}, + "short-4-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":6296.875,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":57.1,"p95Microseconds":108.3,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":1.7531979999999998,"drawMicroseconds":16.641875,"windowWidth":460,"windowHeight":684}, + "short-5-candidate.json": {"scenario":"short","transitionTrace":[{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":157,"windowBottom":164},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423},{"messageLength":31,"windowWidth":460,"windowHeight":168,"actionBottom":448,"windowBottom":455},{"messageLength":5,"windowWidth":460,"windowHeight":104,"actionBottom":416,"windowBottom":423}],"frames":100000,"cpuMilliseconds":6281.25,"allocatedBytesPerFrame":2032.00576,"medianMicroseconds":56.7,"p95Microseconds":100.5,"preparations":101004,"draws":101004,"fontFacts":"owned=True; remaps=0; font=1; baked=2624216277; glyphs=30; size=16","prepMicroseconds":1.629098,"drawMicroseconds":15.949682,"windowWidth":460,"windowHeight":684} + } + } +} diff --git a/records/architecture/acceptance/ISSUE58_MODAL_PERFORMANCE_PROBE.cs.txt b/records/architecture/acceptance/ISSUE58_MODAL_PERFORMANCE_PROBE.cs.txt new file mode 100644 index 00000000..998993d3 --- /dev/null +++ b/records/architecture/acceptance/ISSUE58_MODAL_PERFORMANCE_PROBE.cs.txt @@ -0,0 +1,171 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Collections.Generic; +using System.Numerics; +using System.Text.Json; +using Inno.Adapter.Modules.DotNet; +using Inno.Core.Input; +using Inno.Core.Logging; +using Inno.Editor.Core; +using Inno.Editor.ImGui; +using Inno.Editor.ImGui.ImGuiWidget; +using System.Threading; +using System.Reflection; +using Inno.Extensibility.Modules; +using Inno.Extensibility.Types; +using Inno.Native.ImGui; +using Gui = Inno.Native.ImGui.ImGui; + +[assembly: AssemblyMetadata("Inno.AssemblyDomain", "InnoInternal")] +[assembly: AssemblyMetadata("Inno.AssemblyScope", "Editor")] + +internal static unsafe class Program +{ + private static void Main(string[] args) + { + var currentProcess = Process.GetCurrentProcess(); + long allowed = currentProcess.ProcessorAffinity.ToInt64(); + currentProcess.ProcessorAffinity = new IntPtr(1L << (63 - System.Numerics.BitOperations.LeadingZeroCount((ulong)allowed))); + string owner = Path.GetFullPath(Path.Combine(Path.GetTempPath(), "InnoIssue58Perf")); + string root = Path.GetFullPath(Path.Combine(owner, Guid.NewGuid().ToString("N"))); + if (!root.StartsWith(owner + Path.DirectorySeparatorChar, StringComparison.OrdinalIgnoreCase)) + throw new InvalidOperationException("Invalid probe owner."); + Directory.CreateDirectory(root); + var native = Gui.Raw.CreateContext(null); + try + { + var io = Gui.Raw.GetIO(); + io->DisplaySize = new ImVec2C { X = 1280, Y = 720 }; + io->DeltaTime = 1f / 60f; + io->IniFilename = null; + io->BackendFlags |= (int)ImGuiBackendFlags.RendererHasTextures; + io->Fonts->RendererHasTextures = 1; + using var logs = new LogRouter(); + logs.RegisterSink(new ConsoleLogSink()); + using var modules = new ModuleHost(new ModuleHostOptions { catalogSource = new DotNetAssemblyCatalogSource(typeof(PerfModal).Assembly) }); + using var types = new TypeCatalog(modules, new ReflectionTypeCatalogSource()); + var state = new PerfState(); + using var runtime = new ImGuiEditorRuntime(new EditorContext(root, new EditorKeyboardPolicy(KeyModifier.Control, "Ctrl")), types, logs, [state]); + runtime.Start(); + string shortText = "Preparing the current operation…"; + string longText = string.Join("\n", Enumerable.Repeat("Long diagnostic text / 中文 / current operation. This wraps to the same controlled width.", 8)); + string scrollText = string.Join("\n", Enumerable.Repeat(longText, 12)); + string scenario = args[0]; + string text = scenario == "short" ? shortText : scenario == "scroll" ? scrollText : longText; + var transitionTrace = new List(); + foreach (string message in new[] { "Short", "Short", "First\nSecond\nThird\nFourth\nFifth", "Short" }) + { + state.message = message; + runtime.PrepareFrame(); + Gui.NewFrame(); + runtime.Draw(); + Gui.Render(); + transitionTrace.Add(new { messageLength = message.Length, windowWidth = state.windowSize.X, + windowHeight = state.windowSize.Y, actionBottom = state.actionMax.Y, windowBottom = state.windowMax.Y }); + } + Thread.Sleep(160); + // Compare identical visible work; the old auto-height renderer clips alternating content. + state.fixedSize = true; + for (int frame = 0; frame < 1000; frame++) Draw(frame); + state.prepTicks = state.drawTicks = 0; + double frequency = Stopwatch.Frequency; + var timings = new double[100000]; + int beforeDraws = state.draws; + long before = GC.GetAllocatedBytesForCurrentThread(); + TimeSpan cpuBefore = Process.GetCurrentProcess().TotalProcessorTime; + for (int frame = 0; frame < timings.Length; frame++) + { + long start = Stopwatch.GetTimestamp(); + Draw(frame); + timings[frame] = Stopwatch.GetElapsedTime(start).TotalMicroseconds; + } + double cpu = (Process.GetCurrentProcess().TotalProcessorTime - cpuBefore).TotalMilliseconds; + long allocated = GC.GetAllocatedBytesForCurrentThread() - before; + if (state.draws - beforeDraws != timings.Length) + throw new InvalidOperationException($"The declared workload drew {state.draws-beforeDraws} frames; total={state.draws}, prepared={state.preparations}, classified={typeof(PerfModal).Assembly.TryGetInnoAssemblyClassification(out _, out _)}."); + if (state.windowSize != new Vector2(460f, 684f)) + throw new InvalidOperationException("The paired workload did not preserve its declared visible window area."); + Array.Sort(timings); + File.WriteAllText(args[1], JsonSerializer.Serialize(new + { + scenario, transitionTrace, frames = timings.Length, cpuMilliseconds = cpu, + allocatedBytesPerFrame = (double)allocated / timings.Length, + medianMicroseconds = timings[timings.Length / 2], p95Microseconds = timings[(int)(timings.Length * 0.95)], + preparations = state.preparations, draws = state.draws, fontFacts = state.fontFacts, prepMicroseconds = state.prepTicks / frequency * 1_000_000 / timings.Length, drawMicroseconds = state.drawTicks / frequency * 1_000_000 / timings.Length, + windowWidth = state.windowSize.X, windowHeight = state.windowSize.Y + })); + void Draw(int frame) + { + state.message = scenario == "alternating" && frame % 2 == 0 ? shortText : text; + runtime.PrepareFrame(); + Gui.NewFrame(); + runtime.Draw(); + Gui.Render(); + } + } + finally + { + Gui.Raw.DestroyContext(native); + Directory.Delete(root, true); + } + } +} + +public sealed class PerfState +{ + public bool fixedSize; + public string message = "Short"; + public string? fontFacts; + public long prepTicks; + public long drawTicks; + public int preparations; + public int draws; + public Vector2 windowSize; + public Vector2 windowMax; + public Vector2 actionMax; +} + +[EditorModal("probe.dialog", "Dialog performance")] +public sealed unsafe class PerfModal(PerfState state) : EditorModal +{ + public override Vector2 initialSize => state.fixedSize ? new(460f, 684f) : Vector2.Zero; +#if CANDIDATE + private DialogPresentation m_content; + private DialogLayout m_layout; + public override bool allowScrolling => false; + protected override Vector2? OnPrepare( + EditorContext context, + Vector2 availableContentSize + ) { + long started = Stopwatch.GetTimestamp(); + state.preparations++; + m_content = new(state.message, 0.5f, actionLabel: "Cancel"); + m_layout = EditorUiSession.current.widgets.MeasureDialog(m_content, availableContentSize); + state.prepTicks += Stopwatch.GetTimestamp() - started; + return m_layout.size; + } +#endif + public override bool isVisible => true; + protected override void OnDraw(EditorContext context) + { + long started = Stopwatch.GetTimestamp(); + state.draws++; + state.windowSize = Gui.GetWindowSize(); + state.windowMax = Gui.GetWindowPos() + state.windowSize; +#if CANDIDATE + EditorUiSession.current.widgets.DrawDialog(m_content, m_layout); +#else + EditorUiSession.current.widgets.WrappedText(state.message); + EditorUiSession.current.widgets.CenteredProgressBar(0.5f, new Vector2(-1f, 0f), $"{0.5f:P0}"); + EditorUiSession.current.widgets.CenteredButton("Cancel", EditorUiSession.current.widgets.style.itemSpacing.Y); +#endif + state.actionMax = Gui.GetItemRectMax(); + state.drawTicks += Stopwatch.GetTimestamp() - started; + if(state.draws == 204) { + var ctx = Gui.Raw.GetCurrentContext(); + state.fontFacts = $"owned={ctx->Font->OwnerAtlas->OwnerContext == ctx}; remaps={ctx->Font->RemapPairs.Data.Size}; font={ctx->Font->FontId}; baked={ctx->FontBaked->BakedId}; glyphs={ctx->FontBaked->Glyphs.Size}; size={ctx->FontSize}"; + } + } +} diff --git a/src/composition/editor/features/Inno.Editor.Assets/Inno.Editor.Assets.csproj b/src/composition/editor/features/Inno.Editor.Assets/Inno.Editor.Assets.csproj index 0b740982..f39e41ea 100644 --- a/src/composition/editor/features/Inno.Editor.Assets/Inno.Editor.Assets.csproj +++ b/src/composition/editor/features/Inno.Editor.Assets/Inno.Editor.Assets.csproj @@ -10,6 +10,7 @@ + @@ -17,7 +18,6 @@ - diff --git a/src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs b/src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs index 71c197a5..7be6f4c3 100644 --- a/src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs +++ b/src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportModule.cs @@ -17,7 +17,7 @@ namespace Inno.Editor.Assets; /// Owns sample import validation, publication and rollback independently of its progress window. /// [EditorModule("asset-sample-import", order: 110)] -public sealed class AssetSampleImportModule : EditorModule, IProgress +public sealed class AssetSampleImportModule : EditorModule { private readonly object m_progressLock = new(); private readonly AssetEditingModule m_assets; @@ -30,8 +30,9 @@ public sealed class AssetSampleImportModule : EditorModule, IProgress !m_faulted && !isBusy && m_scripting.state is EditorScriptCompilationState.Ready or EditorScriptCompilationState.Failed; /// - /// Gets an immutable progress message captured under the progress owner lock. + /// Gets a complete immutable progress snapshot under the existing owner lock. /// - public string status - { - get - { - lock (m_progressLock) - return m_status; - } - } - - /// - /// Gets the most recent validation progress fraction. - /// - public float progress + public AssetSampleImportProgress progress { get { @@ -96,26 +85,38 @@ public void Request(AssetPath source) throw new InvalidOperationException("Sample import requires an idle authoring generation."); m_import = m_assets.pipeline.PrepareSampleImport(source); m_canceled = false; - SetProgress(0f, "Preparing sample assets..."); + lock (m_progressLock) + { + m_acceptProgress = true; + m_progress = new(++m_operation, 0f, "Preparing sample assets...", false); + } } /// /// Requests cancellation without releasing work that has not retired. /// - public void Cancel() + private void CancelCurrent() { + if (m_import is null) + return; m_canceled = true; - m_import?.Cancel(); - SetProgress(progress, "Canceling sample import..."); + lock (m_progressLock) + m_progress = m_progress with { status = "Canceling sample import...", cancellationRequested = true }; + m_import.Cancel(); } /// - /// Receives asynchronous compilation progress without accessing live Editor state. + /// Cancels only the import observed by the presentation. /// - /// - /// The compiler stage and completion fraction. + /// + /// The current import identity captured by the caller. /// - public void Report(ScriptCompilationProgress value) => SetProgress(0.2f + value.fraction * 0.6f, value.stage); + public void Cancel(long operationId) + { + if (progress.operationId == operationId) + CancelCurrent(); + } + /// /// Advances completed background phases and publishes the validated import at a frame safe point. /// @@ -143,15 +144,16 @@ protected override void OnUpdate(EditorContext context) SetProgress(0.2f, "Validating sample scripts..."); string physicalSource = Path.Combine(m_assets.pipeline.assetRoot, import.target.localPath); string targetPath = import.target.ToString(); + long operation = progress.operationId; import.BeginValidation(async ( sources, cancellationToken ) => { - ScriptCompilationResult result = await m_compiler.CompileAuthoringGenerationAsync(this, cancellationToken, sources).ConfigureAwait(false); + ScriptCompilationResult result = await m_compiler.CompileAuthoringGenerationAsync(new ImportProgress(this, operation), cancellationToken, sources).ConfigureAwait(false); if (!result.success) throw new InvalidOperationException("Sample script preflight failed:" + Environment.NewLine + string.Join(Environment.NewLine, result.diagnostics.Select(static diagnostic => diagnostic.message))); - SetProgress(0.85f, "Preparing sample history..."); + SetProgress(0.85f, "Preparing sample history...", operation); m_historyPayload = await Task.Run(() => { byte[] archive = AssetSourceArchive.CapturePhysical(physicalSource, isDirectory: true, cancellationToken); @@ -185,7 +187,7 @@ protected override void OnUpdate(EditorContext context) catch (Exception failure) { m_failure = failure; - Cancel(); + CancelCurrent(); if (m_import?.isFaulted == true) ReportFault(failure); } @@ -199,7 +201,7 @@ protected override void OnUpdate(EditorContext context) /// protected override void OnStop(EditorContext context) { - Cancel(); + CancelCurrent(); RetireImport(); } @@ -219,8 +221,17 @@ private void RetireImport() private void ClearImport() { - m_import = null; m_historyPayload?.Dispose(); + lock (m_progressLock) + { + m_acceptProgress = false; + m_progress = m_progress with + { + fraction = m_canceled || m_failure is not null ? m_progress.fraction : 1f, + status = m_failure?.Message ?? (m_canceled ? "Sample import canceled." : "Sample import completed.") + }; + } + m_import = null; m_historyPayload = null; m_failure = null; m_validating = false; @@ -236,12 +247,23 @@ private void ReportFault(Exception failure) private void SetProgress( float progress, - string status + string status, + long? operationId = null ) { lock (m_progressLock) { - m_progress = progress; - m_status = status; + if (!m_acceptProgress || m_progress.cancellationRequested || (operationId is long expected && expected != m_progress.operationId)) + return; + m_progress = m_progress with { fraction = progress, status = status }; } } + + private sealed class ImportProgress( + AssetSampleImportModule owner, + long operation + ) : IProgress + { + /// + public void Report(ScriptCompilationProgress value) => owner.SetProgress(0.2f + value.fraction * 0.6f, value.stage, operation); + } } diff --git a/src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs b/src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs new file mode 100644 index 00000000..ae294eb6 --- /dev/null +++ b/src/composition/editor/features/Inno.Editor.Assets/Samples/AssetSampleImportProgress.cs @@ -0,0 +1,23 @@ +namespace Inno.Editor.Assets; + +/// +/// Contains one atomically captured sample import status. +/// +/// +/// The import identity within its owner. +/// +/// +/// The completed validation and publication fraction. +/// +/// +/// The current stage description. +/// +/// +/// Whether cancellation is draining owned work. +/// +public readonly record struct AssetSampleImportProgress( + long operationId, + float fraction, + string status, + bool cancellationRequested +); diff --git a/src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs b/src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs new file mode 100644 index 00000000..d9e97c02 --- /dev/null +++ b/src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportProgress.cs @@ -0,0 +1,31 @@ +namespace Inno.Editor.Exporting; + +/// +/// Contains one owner-thread export presentation snapshot. +/// +/// +/// The export identity within this service. +/// +/// +/// The last measured completion fraction, or null while the active phase has no measured total. +/// +/// +/// The actual stage or outcome message. +/// +/// +/// The current failure diagnostic, or empty. +/// +/// +/// Whether work still owns resources. +/// +/// +/// Whether cancellation is draining work. +/// +public readonly record struct EditorExportProgress( + long operationId, + float? fraction, + string status, + string error, + bool isBusy, + bool cancellationRequested +); diff --git a/src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs b/src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs index bcfdede7..e5f1194d 100644 --- a/src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs +++ b/src/composition/editor/features/Inno.Editor.Exporting/Runtime/EditorExportService.cs @@ -21,7 +21,11 @@ public sealed class EditorExportService : EditorModule { private readonly BuildPipeline m_buildPipeline; private readonly Logger m_log; - private readonly ConcurrentQueue m_progress = new(); + private readonly ConcurrentQueue<(long operation, BuildProgress value)> m_progress = new(); + private long m_operation; + private string m_status = string.Empty; + private string m_error = string.Empty; + private float? m_fraction; private CancellationTokenSource? m_cancellation; private Task? m_gamePreparation; private Task? m_gameExport; @@ -45,17 +49,23 @@ LogRouter logs /// public bool isGameBusy => m_gamePreparation is not null || m_gameExport is not null; /// - /// Gets the latest owner-thread progress message. + /// Gets one owner-thread snapshot for the current export, including cancellation and action identity. /// - public string status { get; private set; } = string.Empty; - /// - /// Gets the last failure or cancellation diagnostic, or an empty string. - /// - public string error { get; private set; } = string.Empty; + public EditorExportProgress progress => new(m_operation, m_fraction, m_status, m_error, + isGameBusy || isPluginBusy, m_cancellation?.IsCancellationRequested == true); + /// - /// Gets monotonic progress for the current game build, from zero through one. + /// Cancels the observed export only while that operation still owns this service. /// - public float gameProgress { get; private set; } + /// + /// The operation observed by the caller. + /// + public void Cancel(long operationId) + { + if (operationId == m_operation) + CancelCurrent(); + } + /// /// Gets the targets registered by the active Build distribution. /// @@ -98,9 +108,9 @@ public void StartPlugin(PluginBuildRequest request) ArgumentNullException.ThrowIfNull(request); EnsureIdle(); StartCancellation(); - status = "Capturing the current Plugin source and dependency generation..."; - error = string.Empty; - m_pluginExport = m_buildPipeline.BuildPluginAsync(request, new BuildProgressSink(m_progress), m_cancellation!.Token).AsTask(); + m_status = "Capturing the current Plugin source and dependency generation..."; + m_error = string.Empty; + m_pluginExport = m_buildPipeline.BuildPluginAsync(request, new BuildProgressSink(m_progress, m_operation), m_cancellation!.Token).AsTask(); } /// @@ -117,9 +127,9 @@ public void StartGame(GameBuildRequest request) ArgumentNullException.ThrowIfNull(request); EnsureIdle(); StartCancellation(); - gameProgress = 0f; - status = "Checking or preparing the Player Support Pack..."; - error = string.Empty; + m_fraction = null; + m_status = "Checking or preparing the Player Support Pack..."; + m_error = string.Empty; m_pendingGameRequest = request; try { @@ -131,17 +141,6 @@ public void StartGame(GameBuildRequest request) } } - /// - /// Requests cancellation without releasing resources before their owned work drains. - /// - public void Cancel() - { - if (m_cancellation is null) - return; - status = "Canceling export..."; - m_cancellation.Cancel(); - } - private void EnsureIdle() { if (isPluginBusy || isGameBusy) @@ -156,11 +155,14 @@ private void EnsureIdle() /// protected override void OnUpdate(EditorContext context) { - while (m_progress.TryDequeue(out BuildProgress progress)) + while (m_progress.TryDequeue(out var update)) { - status = progress.message; - if (isGameBusy) - gameProgress = MathF.Max(gameProgress, (float)progress.fraction); + if (update.operation != m_operation || m_cancellation is null || m_cancellation.IsCancellationRequested) + continue; + BuildProgress progress = update.value; + m_status = progress.message; + if (isGameBusy || isPluginBusy) + m_fraction = MathF.Max(m_fraction ?? 0f, (float)progress.fraction); } CompletePluginExport(); @@ -249,8 +251,9 @@ private void CompletePluginExport() string outputPath = result.outputPath ?? throw new InvalidOperationException("A successful Plugin build has no output path."); string contentHash = result.contentHash ?? throw new InvalidOperationException("A successful Plugin build has no content identity."); - status = $"Exported {result.assetCount} source files to {outputPath}"; - error = string.Empty; + m_fraction = 1f; + m_status = $"Exported {result.assetCount} source files to {outputPath}"; + m_error = string.Empty; m_log.Write( LogLevel.Info, "Exported Plugin '{0}' to '{1}' ({2} assets, {3} embedded dependencies, {4}).", @@ -259,14 +262,14 @@ private void CompletePluginExport() } catch (OperationCanceledException) { - status = string.Empty; - error = "Plugin export was canceled; no partial package was installed."; + m_status = string.Empty; + m_error = "Plugin export was canceled; no partial package was installed."; m_log.Write(LogLevel.Info, "Plugin export was canceled."); } catch (Exception exception) { - status = string.Empty; - error = exception.Message; + m_status = string.Empty; + m_error = exception.Message; m_log.Write(LogLevel.Error, "Plugin export failed: {0}", [exception]); } finally @@ -291,9 +294,9 @@ private void CompleteGameExport() } string outputPath = result.outputPath ?? throw new InvalidOperationException("A successful game build has no output path."); - status = $"Exported {result.assetCount} assets and {result.runtimeAssemblyCount} runtime assemblies to {outputPath}"; - error = string.Empty; - gameProgress = 1f; + m_status = $"Exported {result.assetCount} assets and {result.runtimeAssemblyCount} runtime assemblies to {outputPath}"; + m_error = string.Empty; + m_fraction = 1f; m_log.Write( LogLevel.Info, "Exported game to '{0}' ({1}, {2} assets, {3} artifact bundles, {4} runtime assemblies).", @@ -302,14 +305,14 @@ private void CompleteGameExport() } catch (OperationCanceledException) { - status = string.Empty; - error = "Game build was canceled; no partial output was installed."; + m_status = string.Empty; + m_error = "Game build was canceled; no partial output was installed."; m_log.Write(LogLevel.Info, "Game build was canceled."); } catch (Exception exception) { - status = string.Empty; - error = exception.Message; + m_status = string.Empty; + m_error = exception.Message; m_log.Write(LogLevel.Error, "Game build failed: {0}", [exception]); } finally @@ -330,22 +333,22 @@ private void CompleteGamePreparation() m_cancellation!.Token.ThrowIfCancellationRequested(); GameBuildRequest request = m_pendingGameRequest ?? throw new InvalidOperationException("The prepared game build has no request."); m_pendingGameRequest = null; - status = "Capturing the authoring generation and compiling runtime scripts..."; - m_gameExport = m_buildPipeline.BuildGameAsync(request, new BuildProgressSink(m_progress), m_cancellation.Token).AsTask(); + m_status = "Capturing the authoring generation and compiling runtime scripts..."; + m_gameExport = m_buildPipeline.BuildGameAsync(request, new BuildProgressSink(m_progress, m_operation), m_cancellation.Token).AsTask(); } catch (OperationCanceledException) { m_pendingGameRequest = null; - status = string.Empty; - error = "Game build was canceled; no partial output was installed."; + m_status = string.Empty; + m_error = "Game build was canceled; no partial output was installed."; m_log.Write(LogLevel.Info, "Game build was canceled while preparing its Support Pack."); ReleaseCancellation(); } catch (Exception exception) { m_pendingGameRequest = null; - status = string.Empty; - error = exception.Message; + m_status = string.Empty; + m_error = exception.Message; m_log.Write(LogLevel.Error, "Game Support Pack preparation failed: {0}", [exception]); ReleaseCancellation(); } @@ -353,10 +356,20 @@ private void CompleteGamePreparation() private void StartCancellation() { + m_operation++; + m_fraction = null; m_cancellation?.Dispose(); m_cancellation = new CancellationTokenSource(); } + private void CancelCurrent() + { + if (m_cancellation is null) + return; + m_status = "Canceling export..."; + m_cancellation.Cancel(); + } + private void ReleaseCancellation() { m_cancellation?.Dispose(); @@ -368,12 +381,15 @@ private void ReportBuildFailure( BuildResult result ) { string message = string.Join(Environment.NewLine, result.diagnostics.Select(static diagnostic => $"[{diagnostic.code}] {diagnostic.message}")); - status = string.Empty; - error = message; + m_status = string.Empty; + m_error = message; m_log.Write(LogLevel.Error, "{0} failed:{1}{2}", [operation, Environment.NewLine, message]); } - private sealed class BuildProgressSink(ConcurrentQueue progress) : IProgress + private sealed class BuildProgressSink( + ConcurrentQueue<(long operation, BuildProgress value)> progress, + long operation + ) : IProgress { /// /// Publishes one progress update to the receiving workflow. @@ -381,6 +397,6 @@ private sealed class BuildProgressSink(ConcurrentQueue progress) /// /// The concrete value read or transformed by this operation. /// - public void Report(BuildProgress value) => progress.Enqueue(value); + public void Report(BuildProgress value) => progress.Enqueue((operation, value)); } } diff --git a/src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs b/src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs new file mode 100644 index 00000000..185e5690 --- /dev/null +++ b/src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScriptCompilationProgress.cs @@ -0,0 +1,27 @@ +namespace Inno.Editor.Scripting; + +/// +/// Captures the progress and cancellation policy of one editor script request. +/// +/// +/// The request identity within the owning script host. +/// +/// +/// The completed fraction of the complete reload workflow. +/// +/// +/// The current stage or failure diagnostic. +/// +/// +/// Whether cancellation is draining owned work. +/// +/// +/// Whether this exact operation currently admits cancellation. +/// +public readonly record struct EditorScriptCompilationProgress( + long operationId, + float fraction, + string status, + bool cancellationRequested, + bool canCancel = false +); diff --git a/src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScripting.cs b/src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScripting.cs index c15d4b23..9d1377c5 100644 --- a/src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScripting.cs +++ b/src/composition/editor/features/Inno.Editor.Scripting/Runtime/EditorScripting.cs @@ -105,11 +105,20 @@ public EditorScriptCompilationState state /// /// Gets the current compiler progress. /// - public float progress => m_manager?.compilationProgress ?? 0f; - /// - /// Gets the current compiler stage. - /// - public string status => m_activationFailure ?? (!m_reloads.CanActivateReload(out string? reason) ? reason ?? "Waiting for Play Mode to stop." : m_manager?.compilationStatus ?? "Initializing project scripting."); + public EditorScriptCompilationProgress progress + { + get + { + ScriptReloadProgress? current = m_manager?.progress; + string message = m_activationFailure ?? (!m_reloads.CanActivateReload(out string? reason) + ? reason ?? "Waiting for Play Mode to stop." + : current?.stage ?? "Initializing project scripting."); + if (m_manager?.isCompilationTakingLong == true && m_activationFailure is null) + message = $"Long-running compilation ({m_manager.compilationElapsed.TotalSeconds:F1}s). {message}"; + return new(current?.operationId ?? 0, current?.fraction ?? 0f, message, + current?.cancellationRequested ?? false, current?.canCancel ?? false); + } + } /// /// Gets the most recently completed compiler result, which may still await activation and retirement verification. /// @@ -164,7 +173,14 @@ internal void ReloadPlugins() } /// - public void CancelCompilation() => m_manager?.CancelCompilation(); + /// + /// The observed request identity; stale actions are ignored. + /// + public void CancelCompilation(long operationId) + { + if (m_manager?.progress.operationId == operationId) + m_manager.CancelCompilation(operationId); + } /// /// Initializes this feature when its owning runtime becomes active. /// diff --git a/src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs b/src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs index 937d7d15..2318d9c1 100644 --- a/src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs +++ b/src/composition/editor/features/Inno.Editor.Scripting/Runtime/IEditorScriptCompilation.cs @@ -35,14 +35,17 @@ public interface IEditorScriptCompilation bool requiresExclusiveProgress { get; } /// - /// Gets the most recent compiler progress fraction in the inclusive range zero to one. + /// Gets one immutable snapshot of the current reload operation and its cancellation policy. /// - float progress { get; } + EditorScriptCompilationProgress progress { get; } /// /// Requests cancellation while retaining ownership until compilation and retirement finish. /// - void CancelCompilation(); + /// + /// The request observed by the presentation; stale requests have no effect. + /// + void CancelCompilation(long operationId); /// /// Queues a fresh cache-aware compilation for a build or simulation workflow. /// @@ -61,10 +64,6 @@ public interface IEditorScriptCompilation /// EditorScriptCompilationState state { get; } - /// - /// Gets a human-readable description of current compiler work or readiness. - /// - string status { get; } /// /// Gets the most recently completed compilation, or before the first attempt completes. diff --git a/src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs b/src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs index c46b1df3..9b7bf5bf 100644 --- a/src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs +++ b/src/composition/editor/framework/Inno.Editor.Core/Extensions/EditorModal.cs @@ -63,6 +63,37 @@ public void Draw(EditorContext context) OnDraw(context); } + /// + /// Captures presentation state before submitting content. Content-sized windows prepare before opening; + /// explicitly sized resizable windows prepare after current input establishes their content bounds. + /// + /// + /// The owner-thread editor context for this frame. + /// + /// + /// The bounded content area in current presentation coordinates, already scaled. + /// + /// + /// The required content size, or null for an explicitly sized window. + /// + /// + /// The context is null. + /// + /// + /// The available extent is not finite and positive. + /// + [ScriptingApiIgnore] + public Vector2? Prepare( + EditorContext context, + Vector2 availableContentSize + ) { + System.ArgumentNullException.ThrowIfNull(context); + if (!float.IsFinite(availableContentSize.X) || !float.IsFinite(availableContentSize.Y) || + availableContentSize.X <= 0f || availableContentSize.Y <= 0f) + throw new System.ArgumentOutOfRangeException(nameof(availableContentSize)); + return OnPrepare(context, availableContentSize); + } + /// /// Draws the modal body inside the runtime-managed centered window. /// @@ -70,4 +101,22 @@ public void Draw(EditorContext context) /// The shared editor context containing current project and frame state. /// protected abstract void OnDraw(EditorContext context); + + /// + /// Captures the state consumed by OnDraw and measures it without drawing or performing domain operations. + /// Content-sized modals must return a finite, nonnegative size. Fixed-size modals may return null. + /// + /// + /// The current owner-thread context. + /// + /// + /// The bounded, already scaled content area. + /// + /// + /// The content extent required by the captured state, or null for explicit sizing. + /// + protected virtual Vector2? OnPrepare( + EditorContext context, + Vector2 availableContentSize + ) => null; } diff --git a/src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs b/src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs index 325cb3f6..1f0cfd39 100644 --- a/src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs +++ b/src/composition/editor/framework/Inno.Editor.Interactions/Runtime/EditorModalExtension.cs @@ -43,6 +43,56 @@ Action quarantine /// public int order { get; } + /// + /// Prepares one presentation frame and quarantines callback failures within its owning presentation boundary. + /// + /// + /// The active owner-thread context. + /// + /// + /// The window policy already captured for this presentation attempt. + /// + /// + /// The bounded content size in current presentation coordinates. + /// + /// + /// The measured extent, or null for explicit sizing or failed preparation. + /// + /// + /// True when preparation succeeded; false when this extension is quarantined. + /// + /// + /// The context is null. + /// + public bool TryPrepare( + EditorContext context, + Presentation presentation, + Vector2 availableContentSize, + out Vector2? contentSize + ) { + ArgumentNullException.ThrowIfNull(context); + contentSize = null; + if (m_isQuarantined) + return false; + try + { + contentSize = m_modal.Prepare(context, availableContentSize); + if (contentSize is Vector2 size && + (!float.IsFinite(size.X) || !float.IsFinite(size.Y) || size.X < 0f || size.Y < 0f)) + throw new InvalidOperationException("Modal preparation returned an invalid content extent."); + if (presentation.initialSize.Y <= 0f && contentSize is null) + throw new InvalidOperationException("A content-sized modal must measure its current content before drawing."); + return true; + } + catch (Exception exception) + { + contentSize = null; + m_isQuarantined = true; + m_quarantine(exception); + return false; + } + } + /// /// Safely captures generation-local modal presentation values. /// @@ -69,6 +119,11 @@ public bool TryGetPresentation(out Presentation presentation) m_modal.allowScrolling, m_modal.initialSize, m_modal.minimumSize); + Vector2 initial = presentation.initialSize; + Vector2 minimum = presentation.minimumSize; + if (!float.IsFinite(initial.X) || !float.IsFinite(initial.Y) || initial.X < 0f || initial.Y < 0f || + !float.IsFinite(minimum.X) || !float.IsFinite(minimum.Y) || minimum.X < 0f || minimum.Y < 0f) + throw new InvalidOperationException("Modal dimensions must be finite and nonnegative; zero leaves that dimension unspecified."); return true; } catch (Exception exception) diff --git a/src/composition/editor/panels/Inno.Editor.Panel.FileBrowser/Samples/AssetSampleImportModal.cs b/src/composition/editor/panels/Inno.Editor.Panel.FileBrowser/Samples/AssetSampleImportModal.cs index cdcae798..f7f5ed54 100644 --- a/src/composition/editor/panels/Inno.Editor.Panel.FileBrowser/Samples/AssetSampleImportModal.cs +++ b/src/composition/editor/panels/Inno.Editor.Panel.FileBrowser/Samples/AssetSampleImportModal.cs @@ -1,33 +1,34 @@ -using EditorUI = Inno.Editor.ImGui.EditorUiSession; -using Inno.Editor.Assets; -using Inno.Editor.Assets.ImGui; using System.Numerics; using Inno.Editor.Core; - +using Inno.Editor.ImGui; +using Inno.Editor.ImGui.ImGuiWidget; +using Inno.Editor.Assets; namespace Inno.Editor.Panel.FileBrowser; [EditorModal("asset-sample-import.progress", "Importing Sample", order: 110)] internal sealed class AssetSampleImportModal(AssetSampleImportModule imports) : EditorModal { - /// - /// Shows progress while the import owns pending background work. - /// + private DialogPresentation m_content; + private DialogLayout m_layout; + private long m_operation; + /// public override bool isVisible => imports.isBusy; - /// - /// Blocks unrelated interaction until import publication or cancellation completes. - /// - public override bool blocksInteraction => true; - - /// - /// Draws progress and cancellation through the shared Editor modal widgets. - /// - /// - /// The current Editor frame and interaction services. - /// + /// + public override bool allowScrolling => false; + /// + protected override Vector2? OnPrepare( + EditorContext context, + Vector2 availableContentSize + ) { + var snapshot = imports.progress; + m_operation = snapshot.operationId; + m_content = new(snapshot.status, snapshot.fraction, actionLabel: "Cancel", actionEnabled: !snapshot.cancellationRequested, cancelOnEscape: true); + m_layout = EditorUiSession.current.widgets.MeasureDialog(m_content, availableContentSize); + return m_layout.size; + } + /// protected override void OnDraw(EditorContext context) { - EditorUI.current.widgets.WrappedText(imports.status); - EditorUI.current.widgets.CenteredProgressBar(imports.progress, new Vector2(-1f, 0f), $"{imports.progress:P0}"); - if (EditorUI.current.widgets.CenteredButton("Cancel", EditorUI.current.widgets.style.itemSpacing.Y)) - imports.Cancel(); + if (EditorUiSession.current.widgets.DrawDialog(m_content, m_layout)) + imports.Cancel(m_operation); } } diff --git a/src/composition/editor/panels/Inno.Editor.Panel.ShaderEditor/Documents/ShaderEditorDocuments.cs b/src/composition/editor/panels/Inno.Editor.Panel.ShaderEditor/Documents/ShaderEditorDocuments.cs index 73cb1336..e36ca273 100644 --- a/src/composition/editor/panels/Inno.Editor.Panel.ShaderEditor/Documents/ShaderEditorDocuments.cs +++ b/src/composition/editor/panels/Inno.Editor.Panel.ShaderEditor/Documents/ShaderEditorDocuments.cs @@ -72,6 +72,7 @@ IEditorPreviewService previews this.previews = previews; } + internal string checkStatus { get; private set; } = "Checking the current Shader draft…"; internal SerializationContext context => AssetSerializationContext.Create(assets); internal ShaderNodeCompilerRegistry nodes => m_nodes ?? throw new InvalidOperationException("Shader documents have not started."); internal ShaderSourceFrontendRegistry frontends => m_frontends ?? throw new InvalidOperationException("Shader documents have not started."); @@ -126,7 +127,11 @@ [new ShaderDiagnostic("SHADER_GRAPH_NODE_INTERFACE", DiagnosticSeverity.Error, f return draft.preview = snapshot; } - internal void ShowCheck(Draft draft) => m_checkDraftId = draft.id; + internal void ShowCheck(Draft draft) + { + m_checkDraftId = draft.id; + checkStatus = "Checking the current Shader draft…"; + } internal bool TryGetCheckDraft(out Draft draft) { draft = null!; @@ -148,6 +153,34 @@ internal void PublishNodeDiagnostics(Draft draft) Diagnostics.Set(draft.id, C_NODE_DIAGNOSTIC_GROUP, diagnostics, draft.path.ToString()); } + private static void PublishCheck( + Draft draft, + EditorShaderDraftCompilationSnapshot snapshot + ) { + var diagnostics = new List(Math.Max(1, snapshot.diagnostics.Count)); + for (int index = 0; index < snapshot.diagnostics.Count; index++) + { + ShaderDiagnostic shader = snapshot.diagnostics[index]; + DiagnosticLocation? location = shader.location is ShaderSourceLocation source ? new(source.assetPath, source.line, source.column) : null; + diagnostics.Add(shader.severity switch + { + DiagnosticSeverity.Info => Diagnostic.Info(shader.code, shader.message, location), + DiagnosticSeverity.Warning => Diagnostic.Warning(shader.code, shader.message, location), + DiagnosticSeverity.Error => Diagnostic.Error(shader.code, shader.message, location), + _ => Diagnostic.Error(shader.code, shader.message, location) + }); + } + + if (diagnostics.Count == 0) + { + diagnostics.Add(snapshot.state == EditorShaderCompilationState.Succeeded + ? Diagnostic.Info("SHADER_CHECK_SUCCEEDED", "Shader check completed without diagnostics.") + : Diagnostic.Error("SHADER_CHECK_FAILED", "Shader check failed without a compiler diagnostic.")); + } + + Diagnostics.Set(draft.id, "Shader Check", diagnostics, draft.path.ToString()); + } + private static void ClearNodeDiagnostics(Draft draft) => Diagnostics.Clear(draft.id, C_NODE_DIAGNOSTIC_GROUP); internal Draft Open(AssetFileEntry entry) => Open(entry, AssetId(entry)); private Draft Open( @@ -394,6 +427,17 @@ protected override void OnStart(EditorContext editor) /// protected override void OnUpdate(EditorContext editor) { + if (TryGetCheckDraft(out Draft checking)) + { + EditorShaderDraftCompilationSnapshot result = Check(checking); + if (result.state != EditorShaderCompilationState.Compiling) + { + PublishCheck(checking, result); + checkStatus = result.state == EditorShaderCompilationState.Succeeded + ? "Shader check completed." : "Shader check failed. See Console diagnostics."; + CloseCheck(); + } + } foreach (AssetPath path in m_pendingImports.ToArray()) { m_pendingImports.Remove(path); diff --git a/src/composition/editor/panels/Inno.Editor.Panel.ShaderEditor/Presentation/ShaderCheckModal.cs b/src/composition/editor/panels/Inno.Editor.Panel.ShaderEditor/Presentation/ShaderCheckModal.cs index e590b3d7..0d3a7349 100644 --- a/src/composition/editor/panels/Inno.Editor.Panel.ShaderEditor/Presentation/ShaderCheckModal.cs +++ b/src/composition/editor/panels/Inno.Editor.Panel.ShaderEditor/Presentation/ShaderCheckModal.cs @@ -1,81 +1,27 @@ -using EditorUI = Inno.Editor.ImGui.EditorUiSession; -using System; -using System.Collections.Generic; -using Inno.Core.Diagnostics; +using System.Numerics; using Inno.Editor.Core; +using Inno.Editor.ImGui; using Inno.Editor.ImGui.ImGuiWidget; -using Inno.Editor.Rendering; -using Inno.Rendering; -using Inno.Rendering.Assets; - namespace Inno.Editor.Panel.ShaderEditor; -/// -/// Displays transient draft-check progress and publishes completed diagnostics to the shared Console. -/// -/// -/// The shader editor documents value used to initialize this instance. -/// + [EditorModal("shader.check", "Checking Shader", order: 220)] internal sealed class ShaderCheckModal(ShaderEditorDocuments documents) : EditorModal { - private const string C_DIAGNOSTIC_GROUP = "Shader Check"; - private string m_status = "Checking the current Shader draft…"; - /// - /// Gets whether this value is visible. - /// + private DialogPresentation m_content; + private DialogLayout m_layout; + /// public override bool isVisible => documents.TryGetCheckDraft(out _); - - /// - /// Renders this feature using the current editor presentation context. - /// - /// - /// The operation scope that provides state, services, and ownership boundaries. - /// - protected override void OnDraw(EditorContext context) - { - _ = context; - if (documents.TryGetCheckDraft(out ShaderEditorDocuments.Draft? draft)) - { - EditorShaderDraftCompilationSnapshot snapshot = documents.Check(draft); - if (snapshot.state == EditorShaderCompilationState.Compiling) - { - m_status = "Checking the current Shader draft…"; - } - else - { - Publish(draft, snapshot); - m_status = snapshot.state == EditorShaderCompilationState.Succeeded ? "Shader check completed." : "Shader check failed. See Console diagnostics."; - documents.CloseCheck(); - } - } - - // Default modal policy is shared with script compilation: the same fixed width, - // centered placement, blocking behavior, fade timing and content-sized height. - EditorUI.current.widgets.WrappedText(m_status); - } - - private static void Publish( - ShaderEditorDocuments.Draft draft, - EditorShaderDraftCompilationSnapshot snapshot + /// + public override bool allowScrolling => false; + /// + protected override Vector2? OnPrepare( + EditorContext context, + Vector2 availableContentSize ) { - var diagnostics = new List(Math.Max(1, snapshot.diagnostics.Count)); - for (int index = 0; index < snapshot.diagnostics.Count; index++) - { - ShaderDiagnostic shader = snapshot.diagnostics[index]; - DiagnosticLocation? location = shader.location is ShaderSourceLocation source ? new(source.assetPath, source.line, source.column) : null; - diagnostics.Add(shader.severity switch - { - DiagnosticSeverity.Info => Diagnostic.Info(shader.code, shader.message, location), - DiagnosticSeverity.Warning => Diagnostic.Warning(shader.code, shader.message, location), - DiagnosticSeverity.Error => Diagnostic.Error(shader.code, shader.message, location), - _ => Diagnostic.Error(shader.code, shader.message, location)}); - } - - if (diagnostics.Count == 0) - { - diagnostics.Add(snapshot.state == EditorShaderCompilationState.Succeeded ? Diagnostic.Info("SHADER_CHECK_SUCCEEDED", "Shader check completed without diagnostics.") : Diagnostic.Error("SHADER_CHECK_FAILED", "Shader check failed without a compiler diagnostic.")); - } - - Diagnostics.Set(draft.id, C_DIAGNOSTIC_GROUP, diagnostics, draft.path.ToString()); + m_content = new(documents.checkStatus); + m_layout = EditorUiSession.current.widgets.MeasureDialog(m_content, availableContentSize); + return m_layout.size; } + /// + protected override void OnDraw(EditorContext context) => EditorUiSession.current.widgets.DrawDialog(m_content, m_layout); } diff --git a/src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs b/src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs index 688b7163..781a6a53 100644 --- a/src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs +++ b/src/composition/editor/presentation/Inno.Editor.ImGui/ImGui.cs @@ -1040,6 +1040,47 @@ public static Vector2 MeasureText(string text) return RawImGui.CalcTextSize(text); } + /// + /// Measures literal text using the same current font and wrap width as wrapped drawing. + /// + /// + /// The literal text, including explicit line breaks. + /// + /// + /// The available width in already scaled presentation coordinates. + /// + /// + /// The copied natural text extent at the specified width. + /// + /// + /// The text is null. + /// + /// + /// The text contains an embedded zero code unit. + /// + /// + /// The text contains invalid Unicode. + /// + /// + /// The width is not finite and positive. + /// + /// + /// No drawing scope is active on the owning UI thread and native context. + /// + /// + /// The active UI session has retired. + /// + public static Vector2 MeasureWrappedText( + string text, + float wrapWidth + ) { + EditorUiSession.current.EnsureDrawing(); + ArgumentNullException.ThrowIfNull(text); + if (!float.IsFinite(wrapWidth) || wrapWidth <= 0f) + throw new ArgumentOutOfRangeException(nameof(wrapWidth)); + return ImGuiUtf8Buffer.MeasureText(text, wrapWidth); + } + /// /// Gets whether the previous item is hovered. /// diff --git a/src/composition/editor/presentation/Inno.Editor.ImGui/Properties/ScriptingApi.cs b/src/composition/editor/presentation/Inno.Editor.ImGui/Properties/ScriptingApi.cs index 10f5afa9..69a33c42 100644 --- a/src/composition/editor/presentation/Inno.Editor.ImGui/Properties/ScriptingApi.cs +++ b/src/composition/editor/presentation/Inno.Editor.ImGui/Properties/ScriptingApi.cs @@ -50,3 +50,6 @@ [assembly: ScriptingApiExport(typeof(ImGuiFont), ScriptingApiScope.Editor)] [assembly: ScriptingApiExport(typeof(ImGuiFontScope), ScriptingApiScope.Editor)] [assembly: ScriptingApiExport(typeof(ImGuiFontStyle), ScriptingApiScope.Editor)] + +[assembly: ScriptingApiExport(typeof(DialogPresentation), ScriptingApiScope.Editor)] +[assembly: ScriptingApiExport(typeof(DialogLayout), ScriptingApiScope.Editor)] diff --git a/src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorModalRenderer.cs b/src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorModalRenderer.cs index b3b110ed..23e29023 100644 --- a/src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorModalRenderer.cs +++ b/src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorModalRenderer.cs @@ -1,8 +1,9 @@ using EditorUI = Inno.Editor.ImGui.EditorUiSession; using System; +using BGCS.Runtime; using System.Numerics; +using System.Runtime.CompilerServices; using Inno.Editor.Core; -using Inno.Editor.ImGui.ImGuiWidget; using Inno.Editor.Interactions; using Inno.Native.ImGui; using NativeImGui = Inno.Native.ImGui.ImGui; @@ -34,6 +35,8 @@ internal static unsafe class EditorModalRenderer /// /// The shared editor context supplied to the modal body. /// + // Current-frame sizing remains on the hot path in Debug hosts as well as optimized products. + [MethodImpl(MethodImplOptions.AggressiveOptimization)] internal static void Draw( string id, string title, @@ -46,43 +49,72 @@ EditorContext context ArgumentException.ThrowIfNullOrWhiteSpace(title); ArgumentNullException.ThrowIfNull(modal); ArgumentNullException.ThrowIfNull(context); + EditorUiSession session = EditorUI.current; + // The runtime established this session; revalidate below after invoking extension preparation. string popupId = $"{title}##{id}"; ImGuiViewport* viewport = NativeImGui.Raw.GetMainViewport(); - Vector2 center = ImGui.FromNative(viewport->WorkPos) + ImGui.FromNative(viewport->WorkSize) * 0.5f; - if (presentation.blocksInteraction) - NativeImGui.OpenPopup(popupId, (int)(ImGuiPopupFlags.NoReopen)); - NativeImGui.SetNextWindowViewport(viewport->ID); - ImGuiCond placementCondition = presentation.canMove || presentation.canResize ? ImGuiCond.Appearing : ImGuiCond.Always; - NativeImGui.SetNextWindowPos(center, (int)(placementCondition), new Vector2(0.5f, 0.5f)); - Vector2 initialSize = presentation.initialSize; - if (initialSize.X > 0f && initialSize.Y > 0f) + var style = NativeImGui.Raw.GetStyle(); + Vector2 workSize = Vector2.Max(Vector2.One, ImGui.FromNative(viewport->WorkSize)); + Vector2 padding = ImGui.FromNative(style->WindowPadding); + Vector2 bounds = Vector2.Max(Vector2.One, workSize - padding * 2f); + Vector2 maximumSize = new(MathF.Floor(bounds.X), MathF.Floor(bounds.Y)); + Vector2 minimumSize = Vector2.Min(presentation.minimumSize * EditorUI.current.widgets.style.zoom, maximumSize); + Vector2 initialSize = presentation.initialSize * EditorUI.current.widgets.style.zoom; + if (presentation.canResize && initialSize.Y <= 0f) { - NativeImGui.SetNextWindowSize(initialSize * EditorUI.current.widgets.style.zoom, (int)(placementCondition)); + using NativeStringLease nativeTitle = Utf8Codec.EncodeNullTerminated(popupId, allowsNull: false); + ImGuiWindow* existing = NativeImGui.Raw.FindWindowByName((sbyte*)nativeTitle.pointer); + if (existing != null && existing->WasActive != 0) + initialSize = ImGui.FromNative(existing->SizeFull); } - else if (!presentation.canResize) + float width = MathF.Floor(Math.Clamp(initialSize.X > 0f ? initialSize.X : EditorUI.current.widgets.style.modalWidth, + MathF.Max(1f, minimumSize.X), maximumSize.X)); + float decorations = NativeImGui.GetFrameHeight(); + Vector2 available = new(MathF.Max(1f, width - padding.X * 2f), + MathF.Max(1f, (initialSize.Y > 0f ? MathF.Min(initialSize.Y, maximumSize.Y) : maximumSize.Y) - padding.Y * 2f - decorations)); + // Explicit resizable windows commit current input in Begin; measure their actual content area afterwards. + bool prepareInside = presentation.canResize && initialSize.Y > 0f; + Vector2? measured = null; + if (!prepareInside && !modal.TryPrepare(context, presentation, available, out measured)) { - NativeImGui.SetNextWindowSize(new Vector2(EditorUI.current.widgets.style.modalWidth, 0f), (int)(ImGuiCond.Always)); + Close(id, title); + return; } - - if (presentation.canResize) + if (!ReferenceEquals(EditorUI.current, session)) + throw new InvalidOperationException("Modal preparation changed the active UI session."); + session.EnsureDrawing(); + bool horizontalOverflow = false; + if (presentation.allowScrolling && measured is Vector2 content) { - Vector2 maximumSize = Vector2.Max(Vector2.One, ImGui.FromNative(viewport->WorkSize)); - Vector2 minimumSize = Vector2.Min(presentation.minimumSize * EditorUI.current.widgets.style.zoom, maximumSize); - ImGui.ConstrainNativeWindowSize(minimumSize, maximumSize, null, null); + horizontalOverflow = content.X > available.X; + bool verticalOverflow = content.Y > available.Y - (horizontalOverflow ? style->ScrollbarSize : 0f); + horizontalOverflow |= content.X > available.X - (verticalOverflow ? style->ScrollbarSize : 0f); } + float height = initialSize.Y > 0f ? initialSize.Y : measured!.Value.Y + padding.Y * 2f + decorations; + if (horizontalOverflow && initialSize.Y <= 0f) + height += style->ScrollbarSize; + Vector2 windowSize = new(width, MathF.Ceiling(Math.Clamp(height, MathF.Max(1f, minimumSize.Y), maximumSize.Y))); + Vector2 center = ImGui.FromNative(viewport->WorkPos) + workSize * 0.5f; + if (presentation.blocksInteraction) + NativeImGui.OpenPopup(popupId, (int)ImGuiPopupFlags.NoReopen); + NativeImGui.SetNextWindowViewport(viewport->ID); + ImGuiCond placementCondition = presentation.canMove || presentation.canResize ? ImGuiCond.Appearing : ImGuiCond.Always; + NativeImGui.SetNextWindowPos(center, (int)placementCondition, new Vector2(0.5f)); + NativeImGui.SetNextWindowSize(windowSize, (int)(presentation.canResize ? ImGuiCond.Appearing : ImGuiCond.Always)); + ImGui.ConstrainNativeWindowSize(minimumSize, maximumSize, null, null); + if (measured is Vector2 extent) + NativeImGui.SetNextWindowContentSize(extent); NativeImGui.PushStyleVar((int)(ImGuiStyleVar.Alpha), alpha); ImGuiWindowFlags flags = ImGuiWindowFlags.NoDocking | ImGuiWindowFlags.NoCollapse; + if (horizontalOverflow) + flags |= ImGuiWindowFlags.HorizontalScrollbar; if (!presentation.allowScrolling) flags |= ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse; if (!presentation.canMove) flags |= ImGuiWindowFlags.NoMove; if (!presentation.canResize) - { flags |= ImGuiWindowFlags.NoResize; - if (presentation.initialSize.X <= 0f || presentation.initialSize.Y <= 0f) - flags |= ImGuiWindowFlags.AlwaysAutoResize; - } bool beganWindow = false; try @@ -99,7 +131,8 @@ EditorContext context beganWindow = !presentation.blocksInteraction || visible; if (visible) { - _ = modal.Draw(context); + if (!prepareInside || modal.TryPrepare(context, presentation, Vector2.Max(Vector2.One, NativeImGui.GetContentRegionAvail()), out _)) + _ = modal.Draw(context); } } finally diff --git a/src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorUiSession.cs b/src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorUiSession.cs index 7b9add85..89bed97a 100644 --- a/src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorUiSession.cs +++ b/src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorUiSession.cs @@ -164,7 +164,11 @@ internal void RequireFramePreparation() return context; } - private ImGuiNativeContext* RequireContext() + /// + /// Borrows the owned native context for the current synchronous presentation operation. + /// The caller must not retain this pointer after that operation. + /// + internal ImGuiNativeContext* RequireContext() { EnsureOwner(); ObjectDisposedException.ThrowIf(m_disposed, this); diff --git a/src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs b/src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs index 03af0b79..21146dd0 100644 --- a/src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs +++ b/src/composition/editor/presentation/Inno.Editor.ImGui/Styling/EditorStyleMetrics.cs @@ -456,15 +456,10 @@ public bool SetZoom(float value) /// public float interactionOverlayThickness => Scale(2f); - /// - /// Gets script compilation modal width. - /// - public float scriptCompilationWidth => Scale(460f); - /// /// Gets the standard centered modal width. /// - public float modalWidth => scriptCompilationWidth; + public float modalWidth => Scale(460f); /// /// Gets the modal fade-in duration in seconds. diff --git a/src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiUtf8Buffer.cs b/src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiUtf8Buffer.cs index 9d8bab8b..a51621f2 100644 --- a/src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiUtf8Buffer.cs +++ b/src/composition/editor/presentation/Inno.Editor.ImGui/TextInput/ImGuiUtf8Buffer.cs @@ -1,4 +1,6 @@ using System; +using System.Numerics; +using System.Runtime.CompilerServices; using System.Text; using System.Buffers; using System.Text.Unicode; @@ -9,6 +11,49 @@ namespace Inno.Editor.ImGui; internal static unsafe class ImGuiUtf8Buffer { + private static readonly UTF8Encoding S_TEXT_ENCODING = new(false, true); + + internal static Vector2 MeasureText( + string text, + float wrapWidth + ) => PresentText(text, wrapWidth, measure: true); + + internal static void DrawText(string text) => _ = PresentText(text, 0f, measure: false); + + [SkipLocalsInit] + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + private static Vector2 PresentText( + string text, + float wrapWidth, + bool measure + ) { + ArgumentNullException.ThrowIfNull(text); + if (text.AsSpan().Contains('\0')) + throw new ArgumentException("Literal native text cannot contain zero code units.", nameof(text)); + int length = checked(S_TEXT_ENCODING.GetByteCount(text) + 1); + byte[]? rented = length > 1024 ? ArrayPool.Shared.Rent(length) : null; + Span buffer = rented is null ? stackalloc byte[length] : rented.AsSpan(0, length); + try + { + int count = S_TEXT_ENCODING.GetBytes(text.AsSpan(), buffer); + buffer[count] = 0; + fixed (byte* value = buffer) + { + ImVec2C size = default; + if (measure) + NativeImGui.Raw.CalcTextSize((sbyte*)value, (sbyte*)value + count, 0, wrapWidth, &size); + else + NativeImGui.Raw.TextUnformatted((sbyte*)value, (sbyte*)value + count); + return new Vector2(size.X, size.Y); + } + } + finally + { + if (rented is not null) + ArrayPool.Shared.Return(rented, clearArray: true); + } + } + internal static bool InputText( string label, string? hint, diff --git a/src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs b/src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs index 5a159493..b04c223a 100644 --- a/src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs +++ b/src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Controls.cs @@ -234,15 +234,8 @@ public bool CenteredButton( throw new ArgumentOutOfRangeException(nameof(topPadding), topPadding, "Top padding cannot be negative."); } - if (topPadding > 0f) - { - NativeImGui.SetCursorPosY(NativeImGui.GetCursorPosY() + topPadding); - } - - float width = NativeImGui.CalcTextSize(label).X + NativeImGui.Raw.GetStyle()->FramePadding.X * 2f; - float offset = MathF.Max(0f, (NativeImGui.GetContentRegionAvail().X - width) * 0.5f); - NativeImGui.SetCursorPosX(NativeImGui.GetCursorPosX() + offset); - return NativeImGui.Button(label); + float width = ImGuiUtf8Buffer.MeasureText(label, -1f).X + NativeImGui.Raw.GetStyle()->FramePadding.X * 2f; + return DrawCenteredButton(label, NativeImGui.GetCursorScreenPos() + new Vector2(0f, topPadding), NativeImGui.GetContentRegionAvail().X, width); } /// @@ -267,11 +260,24 @@ string overlay ) { m_session.EnsureDrawing(); ArgumentNullException.ThrowIfNull(overlay); - NativeImGui.ProgressBar(fraction, size, string.Empty); + ImVec2C nativeSize = ImGui.ToNative(size); + ReadOnlySpan emptyOverlay = "\0"u8; + fixed (byte* empty = emptyOverlay) + NativeImGui.Raw.ProgressBar(fraction, &nativeSize, (sbyte*)empty); Vector2 minimum = NativeImGui.GetItemRectMin(); Vector2 maximum = NativeImGui.GetItemRectMax(); Vector2 textSize = NativeImGui.CalcTextSize(overlay); Vector2 textPosition = minimum + (maximum - minimum - textSize) * 0.5f; ImGui.DrawNativeText(NativeImGui.Raw.GetWindowDrawList(), textPosition, NativeImGui.GetColorU32((int)(ImGuiCol.Text)), overlay); } + + private static bool DrawCenteredButton( + string label, + Vector2 origin, + float availableWidth, + float width + ) { + NativeImGui.SetCursorScreenPos(origin + new Vector2(MathF.Max(0f, (availableWidth - width) * 0.5f), 0f)); + return NativeImGui.Button(label); + } } diff --git a/src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs b/src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs new file mode 100644 index 00000000..36d0de6d --- /dev/null +++ b/src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Dialog.cs @@ -0,0 +1,336 @@ +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using Inno.Native.ImGui; +using NativeGui = Inno.Native.ImGui.ImGui; + +namespace Inno.Editor.ImGui.ImGuiWidget; + +/// +/// Describes immutable content for a measured message dialog. Actions are returned to its owner, never retained as callbacks. +/// +/// +/// The current status or error text. +/// +/// +/// A completed fraction, or null when no progress bar is needed. +/// +/// +/// Whether to show activity without inventing a completed fraction. +/// +/// +/// The optional centered action label. +/// +/// +/// Whether the current operation admits the action. +/// +/// +/// Optional expanded diagnostic text sharing the message scroll owner. +/// +/// +/// Whether Escape activates this action; opt in only for cancellation or dismissal. +/// +public readonly record struct DialogPresentation( + string message, + float? progress = null, + bool indeterminate = false, + string? actionLabel = null, + bool actionEnabled = true, + string? details = null, + bool cancelOnEscape = false +); + +/// +/// Carries a measured dialog layout. Only its required extent is public; drawing mechanics remain owned by the widget. +/// +public readonly struct DialogLayout +{ + internal DialogLayout( + Vector2 size, + float textWidth, + float bodyHeight, + float bodyContentHeight, + float spacing, + float frameHeight, + float actionWidth + ) { + this.size = size; + this.textWidth = textWidth; + this.bodyHeight = bodyHeight; + this.bodyContentHeight = bodyContentHeight; + this.spacing = spacing; + this.frameHeight = frameHeight; + this.actionWidth = actionWidth; + } + + /// + /// Gets the content extent, excluding the window title, border and padding. + /// + public Vector2 size { get; } + internal float textWidth { get; } + internal float bodyHeight { get; } + internal float bodyContentHeight { get; } + internal float spacing { get; } + internal float frameHeight { get; } + internal float actionWidth { get; } +} + +/// +/// Presents measured message dialogs through the owning editor UI session. +/// +public sealed unsafe partial class ImGuiWidget +{ + private const int C_MAX_CACHED_DIALOG_CHARS = 16_384; + private DialogMeasurementKey m_dialogKey; + private DialogMeasurementKey m_previousDialogKey; + private DialogLayout m_dialogLayout; + private DialogLayout m_previousDialogLayout; + + /// + /// Measures current dialog content before its window is opened. The returned geometry must be used with the same presentation. + /// + /// + /// The immutable content captured for this frame. + /// + /// + /// The bounded content area in already scaled presentation coordinates. + /// + /// + /// The bounded current-frame layout, including a single scrolling body when required. + /// + /// + /// The message is null. + /// + /// + /// The message, expanded details or action label contain an embedded zero code unit. + /// + /// + /// The message, expanded details or action label contain invalid Unicode. + /// + /// + /// The available dimensions are not finite and positive, or a determinate progress fraction is outside zero through one. + /// + /// + /// The owning frame, context or thread is not active. + /// + /// + /// The owning UI session has retired. + /// + public DialogLayout MeasureDialog( + DialogPresentation presentation, + Vector2 availableSize + ) { + ImGuiNativeContext* native = m_session.RequireContext(); + if (native->WithinFrameScope == 0 || native->Font == null || native->FontBaked == null) + throw new InvalidOperationException("Dialog measurement requires an active native frame and font."); + ArgumentNullException.ThrowIfNull(presentation.message); + if (presentation.progress is float fraction && (!float.IsFinite(fraction) || fraction < 0f || fraction > 1f)) + throw new ArgumentOutOfRangeException(nameof(presentation), "A determinate progress fraction must be between zero and one."); + if (!float.IsFinite(availableSize.X) || !float.IsFinite(availableSize.Y) || availableSize.X <= 0f || availableSize.Y <= 0f) + throw new ArgumentOutOfRangeException(nameof(availableSize)); + float width = MathF.Max(1f, MathF.Floor(availableSize.X)); + ImGuiStyle* nativeStyle = &native->Style; + float spacing = nativeStyle->ItemSpacing.Y; + float frame = MathF.Ceiling(native->FontSize + nativeStyle->FramePadding.Y * 2f); + bool hasProgress = presentation.progress.HasValue || presentation.indeterminate; + bool hasAction = !string.IsNullOrEmpty(presentation.actionLabel); + ImFont* font = native->Font; + ImFontBaked* baked = native->FontBaked; + // Only value data is retained. Shared or remapped native fonts are measured on every request. + bool memoize = font->OwnerAtlas->OwnerContext == native && font->RemapPairs.Data.Size == 0 && + (long)presentation.message.Length + (presentation.details?.Length ?? 0) + (presentation.actionLabel?.Length ?? 0) <= C_MAX_CACHED_DIALOG_CHARS; + DialogMeasurementKey key = new(presentation.message, presentation.details, presentation.actionLabel, + availableSize, hasProgress, font->FontId, baked->BakedId, baked->Glyphs.Size, + baked->IndexAdvanceX.Size, font->Sources.Size, font->OwnerAtlas->FontNextUniqueId, + native->FontSize, baked->RasterizerDensity, baked->FallbackAdvanceX, + nativeStyle->ItemSpacing.Y, ImGui.FromNative(nativeStyle->FramePadding), nativeStyle->ScrollbarSize); + if (memoize) + { + if (m_dialogLayout.size.X > 0f && m_dialogKey == key) + return m_dialogLayout; + if (m_previousDialogLayout.size.X > 0f && m_previousDialogKey == key) + return m_previousDialogLayout; + } + float footer = (hasProgress ? frame : 0f) + (hasAction ? frame : 0f) + (hasProgress && hasAction ? spacing : 0f); + float body = MeasureDialogBody(presentation, width, spacing); + float availableBody = MathF.Max(0f, MathF.Floor(availableSize.Y - footer - (body > 0f && footer > 0f ? spacing : 0f))); + float textWidth = width; + if (body > availableBody) + { + textWidth = MathF.Max(1f, width - nativeStyle->ScrollbarSize); + body = MeasureDialogBody(presentation, textWidth, spacing); + } + float visibleBody = MathF.Min(body, availableBody); + float height = visibleBody + footer + (visibleBody > 0f && footer > 0f ? spacing : 0f); + float actionWidth = hasAction ? ImGuiUtf8Buffer.MeasureText(presentation.actionLabel!, -1f).X + nativeStyle->FramePadding.X * 2f : 0f; + DialogLayout result = new(new Vector2(width, MathF.Ceiling(height)), textWidth, visibleBody, body, spacing, frame, actionWidth); + if (memoize) + { + m_previousDialogKey = m_dialogKey; + m_previousDialogLayout = m_dialogLayout; + m_dialogKey = key; + m_dialogLayout = result; + } + return result; + } + + /// + /// Draws one prepared message dialog. Text owns one bounded scroll region and actions remain outside it. + /// + /// + /// The same immutable content used for measurement. + /// + /// + /// The measurement captured in this frame and context. + /// + /// + /// True when the enabled action was activated by native button input or its explicitly enabled Escape policy. + /// + /// + /// The message is null. + /// + /// + /// The layout is invalid. + /// + /// + /// The owning frame, context or thread is not active. + /// + /// + /// The owning UI session has retired. + /// + [MethodImpl(MethodImplOptions.AggressiveOptimization)] + public bool DrawDialog( + DialogPresentation presentation, + DialogLayout layout + ) { + m_session.EnsureDrawing(); + ArgumentNullException.ThrowIfNull(presentation.message); + if (!float.IsFinite(layout.size.X) || !float.IsFinite(layout.size.Y) || layout.size.X <= 0f || layout.size.Y < 0f) + throw new ArgumentOutOfRangeException(nameof(layout)); + Vector2 origin = NativeGui.GetCursorScreenPos(); + bool scrolling = layout.bodyContentHeight > layout.bodyHeight; + if (layout.bodyHeight > 0f) + { + if (scrolling) + { + // The modal owns the outer inset; its scrolling body must not apply a second padding. + NativeGui.PushStyleVar((int)ImGuiStyleVar.WindowPadding, Vector2.Zero); + try + { + NativeGui.SetNextWindowContentSize(new Vector2(0f, layout.bodyContentHeight)); + ImVec2C bodySize = ImGui.ToNative(new Vector2(layout.size.X, layout.bodyHeight)); + ReadOnlySpan bodyId = "##dialog-body\0"u8; + bool visible; + fixed (byte* id = bodyId) + visible = NativeGui.Raw.BeginChild((sbyte*)id, &bodySize, 0, 0) != 0; + try + { + if (visible) + DrawDialogBody(presentation, layout.textWidth); + } + finally + { + NativeGui.EndChild(); + } + } + finally + { + NativeGui.PopStyleVar(); + } + } + else + DrawDialogBody(presentation, layout.textWidth); + } + float y = layout.bodyHeight; + if (y > 0f && (presentation.progress.HasValue || presentation.indeterminate || !string.IsNullOrEmpty(presentation.actionLabel))) + y += layout.spacing; + if (presentation.progress.HasValue || presentation.indeterminate) + { + NativeGui.SetCursorScreenPos(origin + new Vector2(0f, y)); + float fraction = presentation.progress ?? 0f; + CenteredProgressBar(presentation.indeterminate ? -(float)NativeGui.GetTime() : fraction, + new Vector2(layout.size.X, layout.frameHeight), presentation.indeterminate ? "Working…" : $"{fraction:P0}"); + y += layout.frameHeight + layout.spacing; + } + bool activated = false; + if (!string.IsNullOrEmpty(presentation.actionLabel)) + { + bool disabled = !presentation.actionEnabled; + if (disabled) + NativeGui.BeginDisabled(true); + try + { + activated = DrawCenteredButton(presentation.actionLabel, origin + new Vector2(0f, y), layout.size.X, layout.actionWidth); + if (presentation.cancelOnEscape && presentation.actionEnabled && NativeGui.IsWindowFocused((int)Inno.Native.ImGui.ImGuiFocusedFlags.RootAndChildWindows) && + NativeGui.IsKeyPressed(Inno.Native.ImGui.ImGuiKey.Escape, false)) + activated = true; + } + finally + { + if (disabled) + NativeGui.EndDisabled(); + } + } + return activated; + } + + private void ClearDialogMeasurements() + { + m_dialogKey = default; + m_previousDialogKey = default; + m_dialogLayout = default; + m_previousDialogLayout = default; + } + + private readonly record struct DialogMeasurementKey( + string message, + string? details, + string? action, + Vector2 available, + bool progress, + uint font, + uint baked, + int glyphs, + int advances, + int sources, + int nextFont, + float fontSize, + float density, + float fallbackAdvance, + float spacing, + Vector2 framePadding, + float scrollbar + ); + + private static float MeasureDialogBody( + DialogPresentation presentation, + float width, + float spacing + ) { + float height = presentation.message.Length == 0 ? 0f : ImGuiUtf8Buffer.MeasureText(presentation.message, width).Y; + if (!string.IsNullOrEmpty(presentation.details)) + height += (height > 0f ? spacing : 0f) + ImGuiUtf8Buffer.MeasureText(presentation.details, width).Y; + return MathF.Ceiling(height); + } + + private static void DrawDialogBody( + DialogPresentation presentation, + float width + ) { + NativeGui.PushTextWrapPos(NativeGui.GetCursorPosX() + width); + try + { + if (presentation.message.Length != 0) + ImGuiUtf8Buffer.DrawText(presentation.message); + if (!string.IsNullOrEmpty(presentation.details)) + { + // Native text already contributes the same inter-item spacing used by measurement. + ImGuiUtf8Buffer.DrawText(presentation.details); + } + } + finally + { + NativeGui.PopTextWrapPos(); + } + } +} diff --git a/src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Lifetime.cs b/src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Lifetime.cs index fb6934f9..09bc0526 100644 --- a/src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Lifetime.cs +++ b/src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Lifetime.cs @@ -33,5 +33,6 @@ internal void Retire() { CancelEdits(); m_treeStatesByWindow.Clear(); + ClearDialogMeasurements(); } } diff --git a/src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs b/src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs index 2a405877..562167ef 100644 --- a/src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs +++ b/src/composition/editor/presentation/Inno.Editor.ImGui/Widgets/ImGuiWidget.Text.cs @@ -457,11 +457,56 @@ string text /// /// Thrown when is . /// + /// + /// The owning UI thread, frame or native context is not active. + /// + /// + /// The owning UI session has retired. + /// public void WrappedText(string text) { m_session.EnsureDrawing(); ArgumentNullException.ThrowIfNull(text); - NativeImGui.PushTextWrapPos(NativeImGui.GetCursorPosX() + MathF.Max(1f, NativeImGui.GetContentRegionAvail().X)); + DrawWrappedText(text, MathF.Max(1f, NativeImGui.GetContentRegionAvail().X)); + } + + /// + /// Draws literal text at an explicitly measured wrap width, independent of a scrolling window's virtual content extent. + /// + /// + /// The literal text captured for the current layout. + /// + /// + /// The measured positive width in current presentation coordinates. + /// + /// + /// The text is null. + /// + /// + /// The width is not finite and positive. + /// + /// + /// The owning UI thread, frame or native context is not active. + /// + /// + /// The owning UI session has retired. + /// + public void WrappedText( + string text, + float wrapWidth + ) { + m_session.EnsureDrawing(); + ArgumentNullException.ThrowIfNull(text); + if (!float.IsFinite(wrapWidth) || wrapWidth <= 0f) + throw new ArgumentOutOfRangeException(nameof(wrapWidth)); + DrawWrappedText(text, wrapWidth); + } + + private static void DrawWrappedText( + string text, + float wrapWidth + ) { + NativeImGui.PushTextWrapPos(NativeImGui.GetCursorPosX() + wrapWidth); try { NativeImGui.TextUnformatted(text); diff --git a/src/composition/editor/presentation/Inno.Editor.Workbench/Exporting/ExportWindowModule.cs b/src/composition/editor/presentation/Inno.Editor.Workbench/Exporting/ExportWindowModule.cs index f83f8353..945dd8a6 100644 --- a/src/composition/editor/presentation/Inno.Editor.Workbench/Exporting/ExportWindowModule.cs +++ b/src/composition/editor/presentation/Inno.Editor.Workbench/Exporting/ExportWindowModule.cs @@ -37,9 +37,9 @@ ProjectSettingsStore m_projectSettings internal ManagedDeploymentId? gameManagedDeployment { get; set; } internal IReadOnlyList availableManagedDeployments => m_exports.GetManagedDeployments(gameTarget); internal IReadOnlyList availableGameTargets => m_exports.availableGameTargets; - internal string status => m_exports.status; - internal string error => m_formError.Length == 0 ? m_exports.error : m_formError; - internal float gameProgress => m_exports.gameProgress; + internal EditorExportProgress progress => m_exports.progress; + internal string status => progress.status; + internal string error => m_formError.Length == 0 ? m_exports.progress.error : m_formError; internal bool includePluginDependencies { get; set; } internal string GetGameTargetDisplayName(BuildTargetId target) => m_exports.GetGameTargetDisplayName(target); @@ -87,19 +87,19 @@ internal void BeginGameExport() m_gameProgressVisible = true; } - internal void CancelPluginExport() => m_exports.Cancel(); - internal void CancelGameExport() => m_exports.Cancel(); + internal void CancelPluginExport(long operationId) => m_exports.Cancel(operationId); + internal void CancelGameExport(long operationId) => m_exports.Cancel(operationId); internal void ClosePlugin() { if (isPluginBusy) - m_exports.Cancel(); + m_exports.Cancel(m_exports.progress.operationId); isPluginVisible = false; } internal void CloseGame() { if (isGameBusy) - m_exports.Cancel(); + m_exports.Cancel(m_exports.progress.operationId); isGameVisible = false; } diff --git a/src/composition/editor/presentation/Inno.Editor.Workbench/Exporting/GameExportProgressModal.cs b/src/composition/editor/presentation/Inno.Editor.Workbench/Exporting/GameExportProgressModal.cs index 2ad8270f..a3d7b9cf 100644 --- a/src/composition/editor/presentation/Inno.Editor.Workbench/Exporting/GameExportProgressModal.cs +++ b/src/composition/editor/presentation/Inno.Editor.Workbench/Exporting/GameExportProgressModal.cs @@ -1,33 +1,40 @@ -using EditorUI = Inno.Editor.ImGui.EditorUiSession; using System.Numerics; using Inno.Editor.Core; - +using Inno.Editor.ImGui; +using Inno.Editor.ImGui.ImGuiWidget; namespace Inno.Editor.Workbench; [EditorModal("export.game.progress", "Exporting Game", order: 311)] internal sealed class GameExportProgressModal(ExportWindowModule window) : EditorModal { - /// - /// Gets whether the export progress overlay should be displayed. - /// + private DialogPresentation m_content; + private DialogLayout m_layout; + private long m_operation; + /// public override bool isVisible => window.isGameProgressVisible; - /// - /// Gets whether export progress prevents interaction with the Editor beneath it. - /// - public override bool blocksInteraction => true; - - /// - /// Draws the current export status and cancellation action while work is active. - /// - /// - /// The active Editor context for the current frame. - /// + /// + public override bool allowScrolling => false; + /// + protected override Vector2? OnPrepare( + EditorContext context, + Vector2 availableContentSize + ) { + var snapshot = window.progress; + m_operation = snapshot.operationId; + m_content = new( + string.IsNullOrEmpty(snapshot.error) ? snapshot.status : snapshot.error, + snapshot.fraction, + indeterminate: snapshot.isBusy && !snapshot.fraction.HasValue, + actionLabel: snapshot.isBusy ? "Cancel" : null, + actionEnabled: !snapshot.cancellationRequested, + cancelOnEscape: true + ); + m_layout = EditorUiSession.current.widgets.MeasureDialog(m_content, availableContentSize); + return m_layout.size; + } + /// protected override void OnDraw(EditorContext context) { - string message = string.IsNullOrEmpty(window.error) ? window.status : window.error; - EditorUI.current.widgets.WrappedText(message); - EditorUI.current.widgets.CenteredProgressBar(window.gameProgress, new Vector2(-1f, 0f), $"{window.gameProgress:P0}"); - if (!window.isGameBusy || !EditorUI.current.widgets.CenteredButton("Cancel", EditorUI.current.widgets.style.itemSpacing.Y)) - return; - window.CancelGameExport(); + if (EditorUiSession.current.widgets.DrawDialog(m_content, m_layout)) + window.CancelGameExport(m_operation); } } diff --git a/src/composition/editor/presentation/Inno.Editor.Workbench/Exporting/PluginExportModal.cs b/src/composition/editor/presentation/Inno.Editor.Workbench/Exporting/PluginExportModal.cs index 2c5e8b59..dcf5d8d1 100644 --- a/src/composition/editor/presentation/Inno.Editor.Workbench/Exporting/PluginExportModal.cs +++ b/src/composition/editor/presentation/Inno.Editor.Workbench/Exporting/PluginExportModal.cs @@ -1,115 +1,173 @@ -using Inno.Editor.ImGui; -using EditorUI = Inno.Editor.ImGui.EditorUiSession; using System; +using System.Collections.Generic; using System.Numerics; using Inno.Editor.Core; -using Inno.Editor.ImGui.ImGuiWidget; +using Inno.Editor.ImGui; using Ui = Inno.Editor.ImGui.ImGui; namespace Inno.Editor.Workbench; + [EditorModal("export.plugin", "Export as Plugin", order: 300)] internal sealed class PluginExportModal(ExportWindowModule window) : EditorModal { private const int C_TEXT_CAPACITY = 4096; - /// - /// Gets whether this implementation is visible. - /// + private const string C_DESCRIPTION = "Packages the current project's complete authored source. Plugin.inno, dependency declarations, settings contributions, and deterministic metadata are generated automatically."; + private const string C_HINT = "Identity comes from Settings > Project > Identity. Other defaults come from Build > Plugin."; + private readonly List m_rows = new(16); + private string m_identity = string.Empty; + private string m_name = string.Empty; + private string m_destination = string.Empty; + private string m_outcome = string.Empty; + private bool m_busy; + private bool m_dependencies; + private long m_operation; + private float m_wrapWidth; + /// public override bool isVisible => window.isPluginVisible; - /// - /// Gets whether this implementation can move. - /// + /// public override bool canMove => true; - /// - /// Gets the preferred initial window size in logical editor units. - /// + /// public override Vector2 initialSize => new(680f, 0f); - - /// - /// Draws this feature using the current editor presentation context. - /// - /// - /// The context that supplies state and services for this operation. - /// - protected override void OnDraw(EditorContext context) - { - EditorUI.current.widgets.WrappedText("Packages the current project's complete authored source. Plugin.inno, dependency declarations, " + "settings contributions, and deterministic metadata are generated automatically."); - Ui.Spacing(); - Ui.BeginDisabled(window.isPluginBusy); - try - { - Ui.Text("Plugin ID"); - EditorUI.current.widgets.ColoredText(Inno.Editor.ImGui.EditorPalette.textDisabled, $"{window.pluginId} (from Project ID)"); - DrawText("Display Name", "plugin_name", window.pluginDisplayName, value => window.pluginDisplayName = value); - DrawText("Destination IPlugin", "plugin_output", window.pluginOutputPath, value => window.pluginOutputPath = value); - bool includeDependencies = window.includePluginDependencies; - if (Ui.Checkbox("Include dependency Plugin packages", ref includeDependencies)) - window.includePluginDependencies = includeDependencies; - } - finally + /// + protected override Vector2? OnPrepare( + EditorContext context, + Vector2 availableContentSize + ) { + var progress = window.progress; + m_operation = progress.operationId; + m_identity = $"{window.pluginId} (from Project ID)"; + m_name = window.pluginDisplayName; + m_destination = window.pluginOutputPath; + m_dependencies = window.includePluginDependencies; + m_busy = window.isPluginBusy; + m_outcome = string.IsNullOrEmpty(progress.error) ? progress.status : progress.error; + float width = availableContentSize.X; + float scrollbar = Ui.GetLayout().scrollbarSize; + float checkboxWidth = Ui.GetFrameHeight() + Ui.GetLayout().itemInnerSpacing.X + + Ui.MeasureText("Include dependency Plugin packages").X; + float height = Present(false, width); + float availableHeight = availableContentSize.Y - (checkboxWidth > width ? scrollbar : 0f); + if (height > availableHeight) { - Ui.EndDisabled(); + width = MathF.Max(1f, width - scrollbar); + height = Present(false, width); } - - EditorUI.current.widgets.ColoredText( - Inno.Editor.ImGui.EditorPalette.textDisabled, - "Identity comes from Settings > Project > Identity. Other defaults come from Build > Plugin." - ); - DrawOutcome(); - DrawButtons(); + m_wrapWidth = width; + return new Vector2(MathF.Max(width, checkboxWidth), height); } + /// + protected override void OnDraw(EditorContext context) => Present(true, m_wrapWidth); - private void DrawOutcome() - { - if (!string.IsNullOrEmpty(window.error)) + private float Present( + bool draw, + float width + ) { + float height = 0f; + int row = 0; + Vector2 origin = draw ? Ui.GetCursorPosition() : Vector2.Zero; + if (!draw) + m_rows.Clear(); + var layout = Ui.GetLayout(); + float gap = layout.itemSpacing.Y; + float frame = Ui.MeasureText("M").Y + layout.framePadding.Y * 2f; + Text(C_DESCRIPTION, true); + Text("Plugin ID"); + Text(m_identity, true); + Field("Display Name", "##plugin_name", ref m_name); + Field("Destination IPlugin", "##plugin_output", ref m_destination); + Row(frame); + if (draw) { - Ui.Spacing(); - EditorUI.current.widgets.WrappedText(window.error); + Ui.BeginDisabled(m_busy); + try + { + if (Ui.Checkbox("Include dependency Plugin packages", ref m_dependencies)) + window.includePluginDependencies = m_dependencies; + } + finally + { + Ui.EndDisabled(); + } } - else if (!string.IsNullOrEmpty(window.status)) + Text(C_HINT, true); + if (m_outcome.Length != 0) + Text(m_outcome, true); + Row(frame); + if (draw) { - Ui.Spacing(); - EditorUI.current.widgets.WrappedText(window.status); + float closeWidth = Ui.MeasureText("Close").X + layout.framePadding.X * 2f; + float actionWidth = Ui.MeasureText(m_busy ? "Cancel" : "Export").X + layout.framePadding.X * 2f; + Ui.SetCursorPosX(Ui.GetCursorPosX() + MathF.Max(0f, width - closeWidth - actionWidth - layout.itemSpacing.X)); + Ui.BeginDisabled(m_busy); + try + { + if (Ui.Button("Close")) + window.ClosePlugin(); + } + finally + { + Ui.EndDisabled(); + } + Ui.SameLine(0f, -1f); + if (Ui.Button(m_busy ? "Cancel" : "Export")) + { + if (m_busy) + window.CancelPluginExport(m_operation); + else + window.BeginPluginExport(); + } } - } + return MathF.Ceiling(height); - private void DrawButtons() - { - Ui.Spacing(); - EditorUiLayout style = Ui.GetLayout(); - float closeWidth = Ui.MeasureText("Close").X + style.framePadding.X * 2f; - string primaryLabel = window.isPluginBusy ? "Cancel" : "Export"; - float exportWidth = Ui.MeasureText(primaryLabel).X + style.framePadding.X * 2f; - Ui.SetCursorPosX(Ui.GetCursorPosX() + MathF.Max(0f, Ui.GetContentRegionAvailable().X - closeWidth - style.itemSpacing.X - exportWidth)); - Ui.BeginDisabled(window.isPluginBusy); - try + void Row(float extent) { - if (Ui.Button("Close")) - window.ClosePlugin(); - } - finally - { - Ui.EndDisabled(); + if (draw) + Ui.SetCursorPosition(origin + new Vector2(0f, m_rows[row++])); + else + { + if (m_rows.Count != 0) + height += gap; + m_rows.Add(height); + height += extent; + } } - - Ui.SameLine(0f, -1f); - if (Ui.Button(primaryLabel)) - { - if (window.isPluginBusy) - window.CancelPluginExport(); + void Text( + string text, + bool wrapped = true + ) { + Row(draw ? 0f : (wrapped ? Ui.MeasureWrappedText(text, width) : Ui.MeasureText(text)).Y); + if (!draw) + return; + if (wrapped) + EditorUiSession.current.widgets.WrappedText(text, width); else - window.BeginPluginExport(); + Ui.Text(text); + } + void Field( + string label, + string id, + ref string value + ) { + Text(label); + Row(frame); + if (!draw) + return; + Ui.BeginDisabled(m_busy); + try + { + Ui.SetNextItemWidth(width); + if (Ui.InputText(id, ref value, C_TEXT_CAPACITY)) + { + if (id == "##plugin_name") + window.pluginDisplayName = value; + else + window.pluginOutputPath = value; + } + } + finally + { + Ui.EndDisabled(); + } } - } - - private static void DrawText( - string label, - string id, - string value, - Action apply - ) { - Ui.Text(label); - Ui.SetNextItemWidth(-1f); - _ = Ui.InputText($"##{id}", ref value, C_TEXT_CAPACITY); - apply(value); } } diff --git a/src/composition/editor/presentation/Inno.Editor.Workbench/Scripting/ScriptCompilationModal.cs b/src/composition/editor/presentation/Inno.Editor.Workbench/Scripting/ScriptCompilationModal.cs index 300be3c2..62116593 100644 --- a/src/composition/editor/presentation/Inno.Editor.Workbench/Scripting/ScriptCompilationModal.cs +++ b/src/composition/editor/presentation/Inno.Editor.Workbench/Scripting/ScriptCompilationModal.cs @@ -1,39 +1,34 @@ -using EditorUI = Inno.Editor.ImGui.EditorUiSession; -using Inno.Editor.Scripting; using System.Numerics; using Inno.Editor.Core; - +using Inno.Editor.ImGui; +using Inno.Editor.ImGui.ImGuiWidget; +using Inno.Editor.Scripting; namespace Inno.Editor.Workbench; -/// -/// Displays blocking script compiler and reload progress with cancellation controls. -/// -/// -/// The scripting used to initialize this instance. -/// [EditorModal("scripting.compilation", "Compiling Scripts", order: 100)] internal sealed class ScriptCompilationModal(IEditorScriptCompilation scripting) : EditorModal { - /// - /// Gets whether this implementation is visible. - /// + private DialogPresentation m_content; + private DialogLayout m_layout; + private long m_operation; + /// public override bool isVisible => scripting.requiresExclusiveProgress; - /// - /// Gets whether blocks interaction is enabled for this implementation. - /// - public override bool blocksInteraction => true; - - /// - /// Draws this feature using the current editor presentation context. - /// - /// - /// The context that supplies state and services for this operation. - /// + /// + public override bool allowScrolling => false; + /// + protected override Vector2? OnPrepare( + EditorContext context, + Vector2 availableContentSize + ) { + var snapshot = scripting.progress; + m_operation = snapshot.operationId; + m_content = new(snapshot.status, snapshot.fraction, actionLabel: "Cancel", actionEnabled: snapshot.canCancel, cancelOnEscape: true); + m_layout = EditorUiSession.current.widgets.MeasureDialog(m_content, availableContentSize); + return m_layout.size; + } + /// protected override void OnDraw(EditorContext context) { - float progress = scripting.progress; - EditorUI.current.widgets.WrappedText(scripting.status); - EditorUI.current.widgets.CenteredProgressBar(progress, new Vector2(-1f, 0f), $"{progress:P0}"); - if (EditorUI.current.widgets.CenteredButton("Cancel", EditorUI.current.widgets.style.itemSpacing.Y)) - scripting.CancelCompilation(); + if (EditorUiSession.current.widgets.DrawDialog(m_content, m_layout)) + scripting.CancelCompilation(m_operation); } } diff --git a/src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs b/src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs index 86fbf5f2..98300a91 100644 --- a/src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs +++ b/src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs @@ -52,11 +52,14 @@ public sealed class ScriptReloadHost : IDisposable private AssemblyModuleHandle? m_editorScriptModule; private string? m_activeCompilationDirectory; private readonly Dictionary m_activeModuleFingerprints = new(StringComparer.Ordinal); - private string m_compilationStatus = "Waiting for script changes."; + private ScriptReloadProgress m_progress = new(0, 0f, "Waiting for script changes.", false); + private long m_progressOperation; + private long m_activeProgressOperation; + private long m_retiringProgressOperation; + private bool m_acceptCompilerProgress; private long m_lastCompileRequestTimestamp; private long m_compilationStartedTimestamp; private TimeSpan m_lastCompilationElapsed; - private float m_compilationProgress; private ScriptReloadRequest m_requestedReload; private bool m_initialCompileRequested; private bool m_publishingGeneration; @@ -175,23 +178,9 @@ public bool isCompilationPending } /// - /// Gets the current compilation progress in the inclusive range from zero to one. + /// Gets one atomically published operation, fraction, stage and cancellation snapshot. /// - public float compilationProgress => Volatile.Read(ref m_compilationProgress); - - /// - /// Gets a short description of the current compilation stage. - /// - public string compilationStatus - { - get - { - string status = Volatile.Read(ref m_compilationStatus); - return isCompilationTakingLong - ? $"Long-running compilation ({compilationElapsed.TotalSeconds:F1}s). {status}" - : status; - } - } + public ScriptReloadProgress progress => Volatile.Read(ref m_progress); /// /// Gets the elapsed duration of the active or most recently completed compilation. @@ -279,8 +268,9 @@ public void Start() : ScriptReloadRequest.ReloadScripting; m_initialCompileRequested = true; m_lastCompileRequestTimestamp = Environment.TickCount64; + Volatile.Write(ref m_progress, new ScriptReloadProgress(++m_progressOperation, 0f, + "Initial scripting cache probe queued.", false)); } - SetCompilationProgress(0f, "Initial scripting cache probe queued."); } } @@ -293,12 +283,21 @@ public void Start() /// /// Thrown after the manager has been disposed. /// - public bool CancelCompilation() + /// + /// The observed request; a stale cancellation is rejected. + /// + public bool CancelCompilation(long operationId) { ObjectDisposedException.ThrowIf(m_disposed, this); CancellationTokenSource? cancellation; lock (m_sync) + { + if (operationId != m_progress.operationId || operationId != m_activeProgressOperation) + return false; cancellation = m_activeCompilationCancellation; + if (cancellation is not null) + SetCompilationProgress(m_progress.fraction, "Canceling script compilation...", operationId, cancellationRequested: true); + } if (cancellation is null) return false; try @@ -309,7 +308,6 @@ public bool CancelCompilation() { return false; } - SetCompilationProgress(compilationProgress, "Canceling script compilation..."); return true; } @@ -364,6 +362,7 @@ public bool TryCompilePending(out Task? compilation) } admission!.Dispose(); ScriptReloadRequest request; + long operation; lock (m_sync) { ThrowIfFaultedLocked(); @@ -381,6 +380,7 @@ public bool TryCompilePending(out Task? compilation) return false; } request = m_requestedReload; + operation = m_progress.operationId; m_requestedReload = ScriptReloadRequest.None; m_initialCompileRequested = false; } @@ -389,13 +389,14 @@ public bool TryCompilePending(out Task? compilation) PluginUnavailabilityPlan? unavailability = request == ScriptReloadRequest.ReloadPlugins ? CapturePluginUnavailabilityPlan() : null; - compilation = CompileAsync(request, unavailability).AsTask(); + compilation = CompileAsync(request, unavailability, operation).AsTask(); return true; } private async ValueTask CompileAsync( ScriptReloadRequest request, PluginUnavailabilityPlan? unavailability, + long operation, CancellationToken cancellationToken = default ) { ObjectDisposedException.ThrowIf(m_disposed, this); @@ -411,8 +412,12 @@ private async ValueTask CompileAsync( Volatile.Write(ref m_isCompiling, 1); Volatile.Write(ref m_compilationStartedTimestamp, Environment.TickCount64); lock (m_sync) + { m_activeCompilationCancellation = linkedCancellation; - SetCompilationProgress(0f, "Preparing script compilation..."); + m_activeProgressOperation = operation; + m_acceptCompilerProgress = true; + } + SetCompilationProgress(0f, "Preparing script compilation...", operation, canCancel: true); ScriptCompilationResult result; try { @@ -423,7 +428,8 @@ private async ValueTask CompileAsync( status ) => SetCompilationProgress( progress * C_COMPILATION_PROGRESS_SHARE, - status)), + progress >= 1f ? "Compilation finished; waiting for generation activation and state recovery." : status, + operation, isCompilerUpdate: true)), effectiveCancellation) .ConfigureAwait(false); } @@ -446,6 +452,7 @@ private async ValueTask CompileAsync( { if (!m_disposed) { + m_acceptCompilerProgress = false; m_lastCompilation = result; if (m_requestedReload != ScriptReloadRequest.None) { @@ -458,18 +465,19 @@ private async ValueTask CompileAsync( m_pendingCompilation = new PendingReload( result, request, + operation, result.success ? null : unavailability); } SetCompilationProgress( - result.success ? C_COMPILATION_PROGRESS_SHARE : 1f, + result.success || unavailability is not null ? C_COMPILATION_PROGRESS_SHARE : progress.fraction, m_requestedReload != ScriptReloadRequest.None ? "Compilation superseded by a queued reload request." : result.success - ? "Script compilation completed." + ? "Script compilation completed; waiting for generation activation and state recovery." : unavailability is not null ? "Compilation failed after a Plugin availability change; the unavailable " + "generation is ready to activate." - : "Script compilation failed."); + : "Script compilation failed.", operation); } } return result; @@ -485,7 +493,10 @@ private async ValueTask CompileAsync( lock (m_sync) { if (ReferenceEquals(m_activeCompilationCancellation, linkedCancellation)) + { m_activeCompilationCancellation = null; + m_acceptCompilerProgress = false; + } } Volatile.Write(ref m_isCompiling, 0); m_compileGate.Release(); @@ -529,17 +540,18 @@ public bool ApplyPendingReload() m_plugins.ApplyPendingChange(); CompletePendingReload(pending); m_reloads.RefreshDiagnostics(); - SetCompilationProgress(1f, "No scripting changes detected."); + SetCompilationProgress(1f, "No scripting changes detected.", pending.operationId); return false; } - SetCompilationProgress(C_STAGING_PROGRESS, "Staging script reload candidates..."); + SetCompilationProgress(C_STAGING_PROGRESS, "Staging script reload candidates...", pending.operationId); using AssemblyReloadSession reload = m_modules.BeginReload( plan.requests.Select(m_moduleSourceFactory).ToArray(), plan.removedModuleNames); - SetCompilationProgress(C_MIGRATION_PROGRESS, "Migrating active editor state..."); + SetCompilationProgress(C_MIGRATION_PROGRESS, "Restoring active editor state...", pending.operationId); IAssemblyUnloadProbe unload = PublishGeneration(reload); m_modules.generations.TrackRetirement(unload); + m_retiringProgressOperation = pending.operationId; m_activeCompilationDirectory = pending.unavailability is null ? pending.compilation.outputDirectory : null; @@ -556,7 +568,7 @@ public bool ApplyPendingReload() !isUnloadVerificationPending ? 1f : C_UNLOAD_VERIFICATION_PROGRESS, !isUnloadVerificationPending ? completedStatus - : completedStatus + " Verifying retired assembly unload..."); + : completedStatus + " Verifying retired assembly unload...", pending.operationId); m_reloads.RefreshDiagnostics(); CompletePendingReload(pending); return true; @@ -665,23 +677,23 @@ public bool AdvanceUnloadVerification(out Exception? failure) failure = m_modules.generations.failure; if (failure is not null) { - SetCompilationProgress(1f, "Generation retirement failed. Restart the host before Play, Build, Export or reload."); + SetCompilationProgress(progress.fraction, "Generation retirement failed. Restart the host before Play, Build, Export or reload."); return true; } try { if (!m_modules.generations.Advance()) { - SetCompilationProgress(C_UNLOAD_VERIFICATION_PROGRESS, "Verifying retired generation unload..."); + SetCompilationProgress(C_UNLOAD_VERIFICATION_PROGRESS, "Verifying retired generation unload...", m_retiringProgressOperation); return false; } - SetCompilationProgress(1f, "Generation publication and retired assembly unload completed."); + SetCompilationProgress(1f, "Generation publication and retired assembly unload completed.", m_retiringProgressOperation); return true; } catch (Exception exception) { failure = exception; - SetCompilationProgress(1f, "Generation retirement failed. Restart the host before Play, Build, Export or reload."); + SetCompilationProgress(progress.fraction, "Generation retirement failed. Restart the host before Play, Build, Export or reload."); return true; } } @@ -736,11 +748,25 @@ private void OnPluginActivationCandidateChanged() } private void SetCompilationProgress( - float progress, - string status + float fraction, + string stage, + long? operationId = null, + bool cancellationRequested = false, + bool isCompilerUpdate = false, + bool canCancel = false ) { - Volatile.Write(ref m_compilationProgress, Math.Clamp(progress, 0f, 1f)); - Volatile.Write(ref m_compilationStatus, status); + lock (m_sync) + { + ScriptReloadProgress current = m_progress; + if (m_disposed || (operationId is long expected && expected != current.operationId)) + return; + if (isCompilerUpdate && (!m_acceptCompilerProgress || current.cancellationRequested)) + return; + Volatile.Write(ref m_progress, new ScriptReloadProgress(current.operationId, + Math.Clamp(fraction, 0f, 1f), stage, current.cancellationRequested || cancellationRequested, + m_activeCompilationCancellation is not null && m_activeProgressOperation == current.operationId && + (canCancel || isCompilerUpdate) && !current.cancellationRequested && !cancellationRequested)); + } } private void QueueReload(ScriptReloadRequest request) @@ -752,13 +778,13 @@ private void QueueReload(ScriptReloadRequest request) if (request > m_requestedReload) m_requestedReload = request; m_lastCompileRequestTimestamp = Environment.TickCount64; + Volatile.Write(ref m_progress, new ScriptReloadProgress(++m_progressOperation, 0f, m_requestedReload switch + { + ScriptReloadRequest.ReloadPlugins => "Plugin and scripting reload queued.", + ScriptReloadRequest.ReloadScripting => "Full scripting reload queued.", + _ => "Scripting recompile queued." + }, false)); } - SetCompilationProgress(0f, request switch - { - ScriptReloadRequest.ReloadPlugins => "Plugin and scripting reload queued.", - ScriptReloadRequest.ReloadScripting => "Full scripting reload queued.", - _ => "Scripting recompile queued." - }); } private ReloadPlan SelectReloadPlan(PendingReload pending) @@ -978,6 +1004,7 @@ private void ThrowIfFaultedLocked() private sealed record PendingReload( ScriptCompilationResult compilation, ScriptReloadRequest request, + long operationId, PluginUnavailabilityPlan? unavailability = null ); diff --git a/src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs b/src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs new file mode 100644 index 00000000..1386ba8d --- /dev/null +++ b/src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadProgress.cs @@ -0,0 +1,27 @@ +namespace Inno.Scripting.Reload; + +/// +/// Atomically published progress owned by one reload request, containing no runtime or extension objects. +/// +/// +/// The host-local reload request sequence; zero precedes the first request. +/// +/// +/// The fraction through compilation, activation and verified retirement. +/// +/// +/// The actual stage or terminal diagnostic. +/// +/// +/// Whether cancellation has been requested and still requires owned work to drain. +/// +/// +/// Whether this exact operation currently admits cancellation. +/// +public sealed record ScriptReloadProgress( + long operationId, + float fraction, + string stage, + bool cancellationRequested, + bool canCancel = false +); diff --git a/tests/Invoke-EditorUiAcceptance.ps1 b/tests/Invoke-EditorUiAcceptance.ps1 index 32066e57..9c7efa13 100644 --- a/tests/Invoke-EditorUiAcceptance.ps1 +++ b/tests/Invoke-EditorUiAcceptance.ps1 @@ -9,6 +9,7 @@ param( [string]$ProductProject, [string[]]$GraphicsApis = @(), [string]$BackendPattern, + [switch]$EditorOnly, [switch]$NoBuild ) @@ -101,12 +102,17 @@ foreach ($selected in $profiles) { 'Lifecycle' { @('Inno.Editor.ImGui.Tests', 'Inno.Editor.Graph.Tests', 'Inno.Editor.PlayMode.Tests', 'Inno.Editor.Scripting.Tests') } 'Performance' { @('Inno.Editor.Interactions.Tests', 'Inno.Editor.PlayMode.Tests', 'Inno.Editor.Scripting.Tests') } } + if ($EditorOnly) { $names = @($names | Where-Object { $_ -notin @('Inno.Build.Tests', 'Inno.Tooling.Architecture.Tests') }) } + if ($EditorOnly -and $selected -eq 'Workflows') { $names += 'Inno.Build.Tests' } $filter = switch ($selected) { 'Visual' { 'FullyQualifiedName~WidgetLayoutTests|FullyQualifiedName~ViewportMetricsTests|Acceptance=Visual' } 'Lifecycle' { 'Acceptance=Lifecycle' } 'Performance' { 'Acceptance=Performance|Category=Performance' } default { '(Acceptance!=Performance)&(Category!=Performance)' } } + if ($EditorOnly -and $selected -eq 'Workflows') { + $filter = "($filter)&(FullyQualifiedName!~Inno.Build.Tests|FullyQualifiedName~BuildPipelineTests.Export|FullyQualifiedName~BuildPipelineTests.EditorShutdownDrainsSupportPackCleanupBeforeReleasingExportServices)" + } $projects = foreach ($name in $names) { $projectFiles = @(Get-ChildItem -LiteralPath (Join-Path $repository 'tests') -Filter "$name.csproj" -Recurse) if ($projectFiles.Count -ne 1) { throw "The suite '$name' does not resolve to one test project." } @@ -116,7 +122,7 @@ foreach ($selected in $profiles) { @{ solution = @{ path = (Join-Path $repository 'InnoEngine.sln'); projects = @($projects) } } | ConvertTo-Json -Depth 4 | Set-Content -LiteralPath $selection -Encoding utf8 if (-not $NoBuild) { - if ($selected -eq 'Contracts') { + if ($selected -eq 'Contracts' -and -not $EditorOnly) { $sourceConfiguration = "Source$Configuration" & $Dotnet build (Join-Path $repository 'InnoEngine.sln') -c $sourceConfiguration "-p:ArtifactsPath=$artifacts" ` *> (Join-Path $stageRoot 'source-build.log') diff --git a/tests/build/Inno.Build.Tests/BuildPipelineTests.ExportPresentation.cs b/tests/build/Inno.Build.Tests/BuildPipelineTests.ExportPresentation.cs index f40a6707..c31f9d47 100644 --- a/tests/build/Inno.Build.Tests/BuildPipelineTests.ExportPresentation.cs +++ b/tests/build/Inno.Build.Tests/BuildPipelineTests.ExportPresentation.cs @@ -1,6 +1,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.IO; +using ImGuiEditorRuntime = Inno.Editor.ImGui.ImGuiEditorRuntime; using System.Numerics; using System.Reflection; using System.Threading; @@ -73,6 +75,86 @@ public unsafe void ExportFormBalancesItsTablesWhenARegisteredTargetLabelFails() } } + [Theory] + [InlineData(1280, 720, 1f)] + [InlineData(320, 480, 2f)] + [Trait("ExternalDependency", "NativeProduct")] + public unsafe void ExportPresentationUsesTheDeclaredWidthAndRealOverflow( + int width, + int height, + float dpi + ) { + var defaults = BuildSettings.CreateDefault("Test Game", "Scenes/Startup.iscene", new BuildTargetId("macos-arm64")); + var settings = new BuildSettingsStore(Path.Combine(m_projectRoot, "Settings.Build.inno"), m_engine.serialization, defaults); + m_engine.modules.Register("Tests.ExportPresentation", [typeof(EditorExportService).Assembly, + Assembly.Load(new AssemblyName("Inno.Editor.Workbench"))]); + var native = NativeGui.Raw.CreateContext(null); + try + { + var io = NativeGui.Raw.GetIO(); + io->DisplaySize = new ImVec2C { X = width, Y = height }; + io->DeltaTime = 0.2f; + io->IniFilename = null; + io->BackendFlags |= (int)ImGuiBackendFlags.RendererHasTextures; + io->Fonts->RendererHasTextures = 1; + using var runtime = new ImGuiEditorRuntime(new EditorContext(m_projectRoot, new EditorKeyboardPolicy(KeyModifier.Control, "Ctrl")), + m_engine.types, m_engine.logs, [m_pipeline, settings, m_settings]); + runtime.Start(); + Assert.True(runtime.interactions.For("editor/main-menu").Execute("export/plugin")); + NativeGui.Raw.GetStyle()->FontScaleDpi = dpi; + for (int frame = 0; frame < 4; frame++) + { + runtime.PrepareFrame(); + NativeGui.NewFrame(); + runtime.Draw(); + NativeGui.Render(); + } + using var title = BGCS.Runtime.Utf8Codec.EncodeNullTerminated("Export as Plugin##export.plugin", allowsNull: false); + var window = NativeGui.Raw.FindWindowByName((sbyte*)title.pointer); + Assert.True(window != null && window->WasActive != 0); + Assert.True(window->Size.X <= width && window->Size.Y <= height); + if (width == 1280) + { + Assert.Equal(680f, window->Size.X); + Assert.InRange(window->ScrollMax.X, 0f, 0.01f); + Assert.InRange(window->ScrollMax.Y, 0f, 0.01f); + } + else + Assert.True(window->ScrollMax.Y > 0f); + Assert.True(runtime.interactions.TryGetModule(out var exports)); + Assert.False(exports!.progress.isBusy); + } + finally + { + NativeGui.Raw.DestroyContext(native); + } + } + + [Fact] + public void ExportPresentationKeepsUnknownProgressAndRejectsStaleCancellation() + { + var defaults = BuildSettings.CreateDefault("Test Game", "Scenes/Startup.iscene", new BuildTargetId("macos-arm64")); + var settings = new BuildSettingsStore(Path.Combine(m_projectRoot, "Settings.Build.inno"), m_engine.serialization, defaults); + m_engine.modules.Register("Tests.ExportProgress", [typeof(EditorExportService).Assembly]); + var context = new EditorContext(m_projectRoot, new EditorKeyboardPolicy(KeyModifier.Control, "Ctrl")); + using var runtime = new Inno.Editor.Interactions.EditorInteractionRuntime(context, m_engine.types, m_engine.logs, + [m_pipeline, settings, m_settings]); + runtime.Start(); + Assert.True(runtime.interactions.TryGetModule(out var exports)); + exports!.StartGame(new GameBuildRequest { profile = CreateProfile(new BuildTargetId("macos-arm64")), + outputDirectory = Path.Combine(m_root, "ProgressOutput") }); + var observed = exports.progress; + Assert.Null(observed.fraction); + Assert.True(observed.isBusy); + exports.Cancel(observed.operationId - 1); + Assert.False(exports.progress.cancellationRequested); + exports.Cancel(observed.operationId); + Assert.True(exports.progress.cancellationRequested); + Assert.False(observed.cancellationRequested); + exports.Stop(context); + Assert.False(exports.progress.isBusy); + } + private static unsafe bool DrawExportFrame( EditorContext context, EditorModalExtension modal diff --git a/tests/ci/New-ValidationSolutionFilter.ps1 b/tests/ci/New-ValidationSolutionFilter.ps1 new file mode 100644 index 00000000..9595a2e3 --- /dev/null +++ b/tests/ci/New-ValidationSolutionFilter.ps1 @@ -0,0 +1,27 @@ +param( + [Parameter(Mandatory)][string]$OutputPath, + [string]$Solution = (Join-Path (Split-Path $PSScriptRoot -Parent) '../InnoEngine.sln') +) + +$ErrorActionPreference = 'Stop' +$solutionPath = [IO.Path]::GetFullPath($Solution) +$root = Split-Path $solutionPath -Parent +$projects = [Collections.Generic.List[string]]::new() +foreach ($line in Get-Content -LiteralPath $solutionPath) { + if ($line -notmatch '^Project\("[^"]+"\) = "[^"]+", "([^"]+\.csproj)"') { continue } + $relative = $Matches[1].Replace('\', '/') + if ($relative -notmatch '^(entry|src|backends|platforms|build|tools|tests)/') { + throw "The solution contains an unclassified validation owner: $relative" + } + $projectPath = [IO.Path]::GetFullPath($relative, $root) + $declaration = [xml](Get-Content -LiteralPath $projectPath -Raw) + if ($declaration.Project.PropertyGroup.IsTestProject -contains 'true') { continue } + $projects.Add($relative) +} +if ($projects.Count -eq 0) { throw 'No validation contracts were selected from the current solution.' } +$output = [IO.Path]::GetFullPath($OutputPath) +if (Test-Path -LiteralPath $output) { throw 'Use a new solution-filter output owner.' } +New-Item -ItemType Directory -Force (Split-Path $output -Parent) | Out-Null +@{ solution = @{ path = $solutionPath; projects = @($projects.ToArray()) } } | + ConvertTo-Json -Depth 4 | Set-Content -LiteralPath $output -Encoding utf8 +Write-Output "Selected $($projects.Count) production and test-support contracts; executable test suites are excluded. MSBuild retains responsibility for the reference closure." diff --git a/tests/ci/Select-ValidationScope.ps1 b/tests/ci/Select-ValidationScope.ps1 new file mode 100644 index 00000000..effb6a5e --- /dev/null +++ b/tests/ci/Select-ValidationScope.ps1 @@ -0,0 +1,96 @@ +param( + [string]$BaseRevision, + [string]$HeadRevision = 'HEAD', + [string[]]$ChangedPath, + [switch]$PullRequest, + [switch]$Full +) + +$ErrorActionPreference = 'Stop' + +function Test-EditorReferenceVisibilityOnly( + [string]$Path, + [string]$Before, + [string]$After +) { + if (-not $Before -or $Path -notmatch '^src/composition/editor/.*\.csproj$') { return $false } + $diff = @(& git diff --unified=0 --no-color --no-ext-diff $Before $After -- $Path) + if ($LASTEXITCODE -ne 0) { throw 'The project visibility comparison failed.' } + $removed = [Collections.Generic.List[string]]::new() + $added = [Collections.Generic.List[string]]::new() + foreach ($line in $diff) { + if ($line -match '^(---|\+\+\+)' -or $line -notmatch '^[+-]') { continue } + if ($line -match '^\-\s*\s*$') { $removed.Add($Matches[1]) } + elseif ($line -match '^\+\s*\s*$') { $added.Add($Matches[1]) } + else { return $false } + } + if ($added.Count -eq 0 -or $added.Count -ne $removed.Count -or + (Compare-Object @($removed | Sort-Object) @($added | Sort-Object))) { return $false } + # Prove unchanged, unconditional edges; do not interpret or resolve an MSBuild dependency graph. + foreach ($revision in @($Before, $After)) { + $text = @(& git show "${revision}:$Path") + if ($LASTEXITCODE -ne 0) { return $false } + try { $xml = [xml]($text -join [Environment]::NewLine) } catch { return $false } + if ($xml.Project.Sdk -ne 'Microsoft.NET.Sdk' -or + @($xml.Project.ChildNodes | Where-Object { $_.NodeType -eq 'Element' -and $_.Name -notin @('PropertyGroup', 'ItemGroup') }).Count -ne 0) { return $false } + foreach ($include in $added) { + $references = @($xml.SelectNodes('//ProjectReference') | Where-Object { $_.Include -ceq $include }) + if ($references.Count -ne 1 -or $references[0].ParentNode.Name -ne 'ItemGroup' -or + $references[0].ParentNode.Attributes.Count -ne 0 -or + $references[0].ParentNode.ParentNode.Name -ne 'Project') { return $false } + } + } + return $true +} + +[string[]]$paths = @() +if ($ChangedPath) { $paths = $ChangedPath } +if (-not $PSBoundParameters.ContainsKey('ChangedPath') -and -not $Full) { + if (-not $BaseRevision) { throw 'A complete comparison base is required for automatic validation.' } + $comparisonBase = $BaseRevision + if ($PullRequest) { + $ancestor = @(& git merge-base $BaseRevision $HeadRevision) + if ($LASTEXITCODE -ne 0 -or $ancestor.Count -ne 1) { throw 'The pull request merge base is unavailable.' } + $comparisonBase = $ancestor[0] + } + # Include both removed and added owners when a file is moved. + $paths = @(& git diff --name-only --no-renames $comparisonBase $HeadRevision --) + if ($LASTEXITCODE -ne 0) { throw 'The complete changed-file set could not be read.' } +} +$editor = $false +$reasons = [Collections.Generic.List[string]]::new() +foreach ($raw in $paths) { + $path = $raw.Replace('\', '/') + if ($path -match '\.(csproj|props|targets|sln|slnf)$') { + if (Test-EditorReferenceVisibilityOnly $path $comparisonBase $HeadRevision) { $editor = $true } + else { $reasons.Add("Build graph: $path") } + } elseif ($path -match '^src/composition/editor/' -or + $path -match '^src/runtime/scripting/Inno\.Scripting\.Reload/') { + $editor = $true + } elseif ($path -match '^tests/editor/' -or + $path -match '^tests/scripting/Inno\.Editor\.Scripting\.Tests/' -or + $path -match '^(docs|records)/' -or $path -eq 'AGENTS.md' -or + $path -eq '.github/workflows/rendering-ci.yml' -or + $path -eq 'tests/build/Inno.Build.Tests/BuildPipelineTests.ExportPresentation.cs' -or + $path -match '^tests/ci/(Select-ValidationScope|Test-ValidationScope|New-ValidationSolutionFilter)\.ps1$' -or + $path -eq 'tests/Invoke-EditorUiAcceptance.ps1') { + # Companions do not broaden a bounded Editor production change. + } else { + $reasons.Add("Shared or unclassified owner: $path") + } +} +if ($Full) { $reasons.Add('Full validation explicitly requested.') } +if (-not $editor) { $reasons.Add('No bounded Editor production change was identified.') } +$profile = if ($reasons.Count -eq 0) { 'editor' } else { 'full' } +[string[]]$scopeReasons = @('Only Editor authoring owners and their verification/documentation changed.') +if ($reasons.Count) { $scopeReasons = $reasons.ToArray() } +[string[]]$omitted = @() +if ($profile -eq 'editor') { + $omitted = @('Editor Release', 'NativeAOT restore', 'ten hot builds', 'unrelated complete test suites', 'Player Support Pack generation') +} +[pscustomobject]@{ + profile = $profile + changedFiles = @($paths) + reasons = $scopeReasons + omitted = $omitted +} diff --git a/tests/ci/Test-ValidationScope.ps1 b/tests/ci/Test-ValidationScope.ps1 new file mode 100644 index 00000000..c8a724a9 --- /dev/null +++ b/tests/ci/Test-ValidationScope.ps1 @@ -0,0 +1,125 @@ +$ErrorActionPreference = 'Stop' +$policy = Join-Path $PSScriptRoot 'Select-ValidationScope.ps1' +$ui = 'src/composition/editor/presentation/Inno.Editor.ImGui/Runtime/EditorModalRenderer.cs' +$cases = @( + @{ paths = @($ui); expected = 'editor' }, + @{ paths = @($ui, 'src/runtime/scripting/Inno.Scripting.Reload/ScriptReloadHost.cs', 'docs/editor/Inno.Editor.ImGui.md'); expected = 'editor' }, + @{ paths = @($ui, 'src/foundation/core/Inno.Core.IO/FileLease.cs'); expected = 'full' }, + @{ paths = @($ui, 'platforms/WindowsX64/build/Removed.cs'); expected = 'full' }, + @{ paths = @($ui, 'src/composition/editor/framework/Inno.Editor.Core/Inno.Editor.Core.csproj'); expected = 'full' }, + @{ paths = @($ui, '.github/actions/setup-dotnet/action.yml'); expected = 'full' }, + @{ paths = @($ui, 'tests/build/Inno.Build.Tests/BuildPipelineTests.ExportPresentation.cs'); expected = 'editor' }, + @{ paths = @('docs/README.md'); expected = 'full' }, + @{ paths = @('unknown.file'); expected = 'full' }, + @{ paths = @(); expected = 'full' } +) +foreach ($case in $cases) { + $actual = & $policy -ChangedPath $case.paths + if ($actual.profile -ne $case.expected) { throw "Unexpected selection for $($case.paths -join ', '): $($actual.profile)" } +} +if ((& $policy -ChangedPath @($ui) -Full).profile -ne 'full') { throw 'Manual full validation was not honored.' } +# Keep the tiny, test-owned Git fixture for inspection on failure. +$owner = Join-Path ([IO.Path]::GetTempPath()) ('InnoCiScope-' + [Guid]::NewGuid().ToString('N')) +New-Item -ItemType Directory $owner | Out-Null +$contractFilter = Join-Path $PSScriptRoot 'New-ValidationSolutionFilter.ps1' +$contractOutput = Join-Path $owner 'contracts.slnf' +& $contractFilter -OutputPath $contractOutput +$contracts = Get-Content -LiteralPath $contractOutput -Raw | ConvertFrom-Json +if ($contracts.solution.projects.Count -le 0) { throw 'The current contract solution filter is empty.' } +$solutionRoot = Split-Path $contracts.solution.path -Parent +foreach ($relative in $contracts.solution.projects) { + $declaration = [xml](Get-Content -LiteralPath (Join-Path $solutionRoot $relative) -Raw) + if ($declaration.Project.PropertyGroup.IsTestProject -contains 'true') { + throw "An executable test suite entered the contract build: $relative" + } +} +$trackedTests = @(& git -C $solutionRoot ls-files -- tests) +if ($LASTEXITCODE -ne 0) { throw 'The tracked test-contract inventory could not be read.' } +$expectedSupport = @($trackedTests | Where-Object { + if ($_ -notlike '*.csproj') { return $false } + $declaration = [xml](Get-Content -LiteralPath (Join-Path $solutionRoot $_) -Raw) + return $declaration.Project.PropertyGroup.IsTestProject -notcontains 'true' +}) +if ($expectedSupport.Count -eq 0) { throw 'The test contract fixture unexpectedly has no support owners.' } +foreach ($relative in $expectedSupport) { + if ($contracts.solution.projects -notcontains $relative) { throw "A Wiki test-support contract is missing: $relative" } +} +$invalidSolution = Join-Path $owner 'invalid.sln' +'Project("{00000000-0000-0000-0000-000000000000}") = "Unknown", "unknown/Unknown.csproj", "{00000000-0000-0000-0000-000000000000}"' | + Set-Content -LiteralPath $invalidSolution +$rejected = $false +try { & $contractFilter -Solution $invalidSolution -OutputPath (Join-Path $owner 'invalid.slnf') } +catch { $rejected = $_.Exception.Message -like '*unclassified validation owner*' } +if (-not $rejected) { throw 'An unknown production owner was silently omitted.' } +'No projects' | Set-Content -LiteralPath $invalidSolution +$rejected = $false +try { & $contractFilter -Solution $invalidSolution -OutputPath (Join-Path $owner 'empty.slnf') } +catch { $rejected = $_.Exception.Message -like '*No validation contracts*' } +if (-not $rejected) { throw 'An empty production filter was accepted.' } +Push-Location $owner +try { + & git init --quiet + if ($LASTEXITCODE -ne 0) { throw 'Git fixture initialization failed.' } + New-Item -ItemType Directory -Force 'platforms/Example', 'src/composition/editor/presentation' | Out-Null + 'source' | Set-Content 'platforms/Example/Old.cs' + & git add . + & git -c user.name='Aaron Liao' -c user.email='hsuankailiao@gmail.com' commit --quiet -m 'test(ci): seed owner' + if ($LASTEXITCODE -ne 0) { throw 'Git fixture commit failed.' } + $baseline = (& git rev-parse HEAD).Trim() + Move-Item -LiteralPath 'platforms/Example/Old.cs' -Destination 'src/composition/editor/presentation/New.cs' + & git add -A + & git -c user.name='Aaron Liao' -c user.email='hsuankailiao@gmail.com' commit --quiet -m 'test(ci): move owner' + if ($LASTEXITCODE -ne 0) { throw 'Git fixture move failed.' } + $moved = & $policy -BaseRevision $baseline + if ($moved.profile -ne 'full' -or $moved.changedFiles -notcontains 'platforms/Example/Old.cs') { throw 'A moved owner escaped validation.' } + & git checkout --quiet -b ui-only $baseline + if ($LASTEXITCODE -ne 0) { throw 'The UI branch fixture could not be created.' } + New-Item -ItemType Directory -Force 'src/composition/editor/presentation' | Out-Null + 'UI' | Set-Content 'src/composition/editor/presentation/Ui.cs' + & git add . + & git -c user.name='Aaron Liao' -c user.email='hsuankailiao@gmail.com' commit --quiet -m 'test(ci): add editor change' + if ($LASTEXITCODE -ne 0) { throw 'The UI fixture commit failed.' } + $uiHead = (& git rev-parse HEAD).Trim() + & git checkout --quiet -b base-advanced $baseline + if ($LASTEXITCODE -ne 0) { throw 'The advanced base fixture could not be created.' } + New-Item -ItemType Directory -Force 'src/foundation' | Out-Null + 'Core' | Set-Content 'src/foundation/Core.cs' + & git add . + & git -c user.name='Aaron Liao' -c user.email='hsuankailiao@gmail.com' commit --quiet -m 'test(ci): advance shared base' + if ($LASTEXITCODE -ne 0) { throw 'The advanced base fixture commit failed.' } + $baseHead = (& git rev-parse HEAD).Trim() + if ((& $policy -BaseRevision $baseHead -HeadRevision $uiHead -PullRequest).profile -ne 'editor') { + throw 'Unrelated base commits broadened pull request validation.' + } + if ((& $policy -BaseRevision $baseHead -HeadRevision $uiHead).profile -ne 'full') { + throw 'A direct push comparison lost its removed shared owner.' + } + & git checkout --quiet ui-only + if ($LASTEXITCODE -ne 0) { throw 'The reference fixture branch is unavailable.' } + $project = 'src/composition/editor/presentation/Ui.csproj' + 'net10.0' + + [Environment]::NewLine + ' ' + + [Environment]::NewLine + '' | Set-Content $project + & git add . + & git -c user.name='Aaron Liao' -c user.email='hsuankailiao@gmail.com' commit --quiet -m 'test(ci): seed reference boundary' + if ($LASTEXITCODE -ne 0) { throw 'The reference baseline commit failed.' } + $referenceBase = (& git rev-parse HEAD).Trim() + (Get-Content $project -Raw).Replace('Dependency.csproj" />', 'Dependency.csproj" PrivateAssets="compile" />') | Set-Content $project -NoNewline + & git add . + & git -c user.name='Aaron Liao' -c user.email='hsuankailiao@gmail.com' commit --quiet -m 'test(ci): tighten editor visibility' + if ($LASTEXITCODE -ne 0) { throw 'The visibility fixture commit failed.' } + if ((& $policy -BaseRevision $referenceBase).profile -ne 'editor') { throw 'A proved visibility-only correction broadened validation.' } + (Get-Content $project -Raw).Replace('net10.0', 'net11.0') | Set-Content $project -NoNewline + & git add . + & git -c user.name='Aaron Liao' -c user.email='hsuankailiao@gmail.com' commit --quiet -m 'test(ci): change framework' + if ($LASTEXITCODE -ne 0) { throw 'The framework fixture commit failed.' } + if ((& $policy -BaseRevision $referenceBase).profile -ne 'full') { throw 'A framework change escaped full validation.' } +} finally { + Pop-Location +} +$resolved = [IO.Path]::GetFullPath($owner) +$parent = [IO.Path]::GetFullPath([IO.Path]::GetTempPath()) +if (-not $resolved.StartsWith($parent, [StringComparison]::OrdinalIgnoreCase) -or + [IO.Path]::GetFileName($resolved) -notlike 'InnoCiScope-*') { throw 'Invalid fixture cleanup owner.' } +Remove-Item -LiteralPath $resolved -Recurse -Force +Write-Output 'Validation scope policy: 20 cases passed, including test-support contracts, visibility proofs, real moves and PR bases.' diff --git a/tests/editor/Inno.Editor.ImGui.Tests/DynamicModalTests.cs b/tests/editor/Inno.Editor.ImGui.Tests/DynamicModalTests.cs new file mode 100644 index 00000000..5cdff697 --- /dev/null +++ b/tests/editor/Inno.Editor.ImGui.Tests/DynamicModalTests.cs @@ -0,0 +1,426 @@ +using System; +using System.IO; +using System.Numerics; +using System.Threading; +using Inno.Adapter.Modules.DotNet; +using Inno.Core.Input; +using Inno.Core.Logging; +using Inno.Editor.Core; +using Inno.Editor.ImGui.ImGuiWidget; +using Inno.Extensibility.Modules; +using Inno.Extensibility.Types; +using Inno.Native.ImGui; +using Xunit; +using Xunit.Abstractions; +using System.Text.Json; +using NativeGui = Inno.Native.ImGui.ImGui; + +namespace Inno.Editor.ImGui.Tests; + +public sealed unsafe class DynamicModalTests +{ + private readonly ITestOutputHelper m_output; + public DynamicModalTests(ITestOutputHelper output) => m_output = output; + [Fact] + [Trait("Acceptance", "Visual")] + public void ChangedContentFitsOnTheTransitionFrameThroughTheActualRenderer() + { + using var host = new ModalHost(); + host.Frame(); + host.Frame(); + float shortHeight = host.state.windowSize.Y; + host.state.message = "First line\nSecond line\nThird line\nFourth line\nFifth line"; + host.Frame(); + Assert.True(host.state.windowSize.Y > shortHeight + 20f); + Assert.True(host.state.actionMax.Y <= host.state.windowMax.Y, "The current action was clipped by the previous message height."); + host.state.message = "Short"; + host.Frame(); + Assert.Equal(shortHeight, host.state.windowSize.Y); + Assert.Equal(host.state.draws, host.state.preparations); + } + + [Theory] + [InlineData(1280, 720)] + [InlineData(1920, 1080)] + [InlineData(640, 480)] + [Trait("Acceptance", "Visual")] + public void ScaleMatrixBoundsCurrentTextAndActions( + int width, + int height + ) { + foreach (float zoom in new[] { 0.75f, 0.85f, 0.9f, 1f, 1.1f, 1.25f, 1.5f }) + foreach (float dpi in new[] { 1f, 1.25f, 1.5f, 2f }) + { + using var host = new ModalHost(width, height); + host.state.zoom = zoom; + NativeGui.Raw.GetStyle()->FontScaleDpi = dpi; + host.Frame(); + host.Frame(); + string[] messages = ["Short", "First\nSecond", new string('W', 600), "中文状态 / café / Ελληνικά\n" + new string('x', 4000), "", "Short"]; + foreach (string text in messages) + { + host.state.message = text; + host.Frame(); + m_output.WriteLine(JsonSerializer.Serialize(new + { + width, height, zoom, dpi, messageLength = text.Length, + wrapWidth = host.state.wrapWidth, bodyHeight = host.state.bodyHeight, + bodyContentHeight = host.state.bodyContentHeight, + windowWidth = host.state.windowSize.X, windowHeight = host.state.windowSize.Y, + actionMinimumX = host.state.actionMin.X, actionMinimumY = host.state.actionMin.Y, + actionMaximumX = host.state.actionMax.X, actionMaximumY = host.state.actionMax.Y, + scrollMaxX = host.state.scrollMaxX + })); + Assert.True(host.state.windowSize.X <= width && host.state.windowSize.Y <= height); + Assert.True(host.state.actionMax.Y <= host.state.windowMax.Y + 1f, + $"Action exceeded the window: zoom={zoom}, dpi={dpi}, message length={text.Length}."); + Assert.InRange(host.state.scrollMaxX, 0f, 0.01f); + Vector2 first = host.state.windowSize; + host.Frame(); + Assert.Equal(first, host.state.windowSize); + } + } + } + + [Fact] + [Trait("Acceptance", "Lifecycle")] + public void ReopeningAndFailuresPreserveTheOwnedNativeScopes() + { + using var host = new ModalHost(); + for (int cycle = 0; cycle < 100; cycle++) + { + host.state.visible = true; + host.Frame(); + host.state.visible = false; + host.Frame(); + Thread.Sleep(510); + host.Frame(); + Assert.False(host.state.popupOpen); + } + host.state.visible = true; + host.state.rejectPreparation = true; + int draws = host.state.draws; + host.Frame(); + Assert.Equal(draws, host.state.draws); + host.state.rejectPreparation = false; + host.Refresh(); + host.Frame(); + Assert.True(host.state.draws > draws); + host.state.rejectDraw = true; + host.Frame(); + host.state.rejectDraw = false; + host.Refresh(); + host.Frame(); + } + + [Fact] + [Trait("Acceptance", "Visual")] + public void CurrentActionRectangleCancelsOnceAndBecomesDisabled() + { + using var host = new ModalHost(); + host.Frame(); + host.Frame(); + host.state.message = "Line one\nLine two\nLine three"; + host.Frame(); + Vector2 hit = (host.state.actionMin + host.state.actionMax) * 0.5f; + var io = NativeGui.Raw.GetIO(); + NativeGui.Raw.AddMousePosEvent(io, hit.X, hit.Y); + NativeGui.Raw.AddMouseButtonEvent(io, 0, 1); + host.Frame(); + NativeGui.Raw.AddMouseButtonEvent(io, 0, 0); + host.Frame(); + Assert.Equal(1, host.state.actions); + NativeGui.Raw.AddMouseButtonEvent(io, 0, 1); + host.Frame(); + NativeGui.Raw.AddMouseButtonEvent(io, 0, 0); + host.Frame(); + Assert.Equal(1, host.state.actions); + } + + [Fact] + [Trait("Acceptance", "Visual")] + public void DetailsActivityAndActionChangesUseTheCurrentFrameLayout() + { + using var host = new ModalHost(); + host.Frame(); + host.Frame(); + host.state.details = new string('D', 8000); + host.state.indeterminate = true; + host.Frame(); + Assert.True(host.state.bodyContentHeight > host.state.bodyHeight); + Assert.True(host.state.actionMax.Y <= host.state.windowMax.Y); + host.state.details = null; + host.state.showAction = false; + host.state.showProgress = false; + host.state.indeterminate = false; + host.state.message = string.Empty; + host.Frame(); + Assert.Equal(0f, host.state.layout.size.Y); + host.state.showAction = true; + host.state.message = "Cancel using the keyboard"; + host.Frame(); + var io = NativeGui.Raw.GetIO(); + NativeGui.Raw.AddKeyEvent(io, Inno.Native.ImGui.ImGuiKey.Escape, 1); + host.Frame(); + NativeGui.Raw.AddKeyEvent(io, Inno.Native.ImGui.ImGuiKey.Escape, 0); + host.Frame(); + Assert.Equal(1, host.state.actions); + } + + [Fact] + [Trait("Acceptance", "Visual")] + public void TabAndEnterActivateTheCurrentEnabledAction() + { + using var host = new ModalHost(); + var io = NativeGui.Raw.GetIO(); + io->ConfigFlags |= (int)Inno.Native.ImGui.ImGuiConfigFlags.NavEnableKeyboard; + host.Frame(); + host.Frame(); + NativeGui.Raw.AddKeyEvent(io, Inno.Native.ImGui.ImGuiKey.Tab, 1); + host.Frame(); + NativeGui.Raw.AddKeyEvent(io, Inno.Native.ImGui.ImGuiKey.Tab, 0); + host.Frame(); + NativeGui.Raw.AddKeyEvent(io, Inno.Native.ImGui.ImGuiKey.Enter, 1); + host.Frame(); + NativeGui.Raw.AddKeyEvent(io, Inno.Native.ImGui.ImGuiKey.Enter, 0); + host.Frame(); + Assert.Equal(1, host.state.actions); + } + + [Fact] + [Trait("Acceptance", "Visual")] + public void ExplicitWidthAndResizableWindowPolicyArePreserved() + { + using var host = new ModalHost(); + host.state.initialSize = new(680, 0); + host.Frame(); + host.Frame(); + Assert.Equal(680, host.state.windowSize.X); + host.state.initialSize = new(600, 300); + host.state.resizable = true; + host.state.visible = false; + host.Frame(); + Thread.Sleep(510); + host.Frame(); + host.state.visible = true; + host.Frame(); + host.Frame(); + Vector2 fixedSize = host.state.windowSize; + host.state.message = new string('W', 1000); + host.Frame(); + Assert.Equal(fixedSize, host.state.windowSize); + Assert.True(host.state.actionMax.Y <= host.state.windowMax.Y); + } + + [Fact] + public void FontAndZoomChangesInvalidatePreparedMeasurementsInTheSameSession() + { + using var host = new ModalHost(); + host.state.message = new string('W', 60); + host.Frame(); + host.Frame(); + float originalActionWidth = host.state.actionMax.X - host.state.actionMin.X; + float originalHeight = host.state.layout.size.Y; + var io = NativeGui.Raw.GetIO(); + var configuration = NativeGui.Raw.ImFontConfig(); + try + { + configuration->SizePixels = 16f; + configuration->GlyphExtraAdvanceX = 8f; + io->FontDefault = NativeGui.Raw.AddFontDefault(io->Fonts, configuration); + Assert.True(io->FontDefault != null); + } + finally + { + NativeGui.Raw.Destroy(configuration); + } + host.Frame(); + host.Frame(); + Assert.True(host.state.actionMax.X - host.state.actionMin.X > originalActionWidth); + Assert.True(host.state.layout.size.Y > originalHeight); + host.state.zoom = 1.5f; + host.Frame(); + host.Frame(); + Assert.Equal(690f, host.state.windowSize.X); + Assert.True(host.state.actionMax.Y <= host.state.windowMax.Y); + } + + [Fact] + public void InvalidWindowDimensionsAreQuarantinedBeforeNativeLayout() + { + using var host = new ModalHost(); + host.state.initialSize = new(float.NaN, 0f); + host.Frame(); + Assert.Equal(0, host.state.draws); + Assert.Equal(0, host.state.preparations); + host.state.initialSize = Vector2.Zero; + host.Refresh(); + host.Frame(); + Assert.True(host.state.draws > 0); + } + + [Fact] + public void InvalidLiteralTextFailsWithoutCorruptingTheNextNativeFrame() + { + using var host = new ModalHost(); + host.Frame(); + foreach (string text in new[] { "zero\0text", "invalid\ud800" }) + { + int draws = host.state.draws; + host.state.message = text; + host.Frame(); + Assert.Equal(draws, host.state.draws); + host.state.message = "Valid text"; + host.Refresh(); + host.Frame(); + Assert.True(host.state.draws > draws); + } + } + + [Fact] + public void IndependentSessionsDoNotSharePreparedDialogContent() + { + using var first = new ModalHost(); + using var second = new ModalHost(); + first.state.message = "First session"; + second.state.message = "Second session\nWith another line"; + first.Frame(); + second.Frame(); + first.Frame(); + Assert.NotEqual(first.state.windowSize.Y, second.state.windowSize.Y); + Assert.Equal("First session", first.state.content.message); + Assert.Equal("Second session\nWith another line", second.state.content.message); + } + + private sealed class ModalHost : IDisposable + { + private readonly string m_root = Path.Combine(Path.GetTempPath(), "InnoModalTests", Guid.NewGuid().ToString("N")); + private readonly ImGuiNativeContext* m_native; + private readonly ModuleHost m_modules; + private readonly TypeCatalog m_types; + private readonly LogRouter m_logs = new(); + private readonly ImGuiEditorRuntime m_runtime; + internal readonly DynamicModalState state = new(); + + internal ModalHost( + int width = 1280, + int height = 720 + ) { + Directory.CreateDirectory(m_root); + m_native = NativeGui.Raw.CreateContext(null); + NativeGui.Raw.SetCurrentContext(m_native); + var io = NativeGui.Raw.GetIO(); + io->DisplaySize = new ImVec2C { X = width, Y = height }; + io->DeltaTime = 0.2f; + io->IniFilename = null; + io->BackendFlags |= (int)ImGuiBackendFlags.RendererHasTextures; + io->Fonts->RendererHasTextures = 1; + m_modules = new ModuleHost(new ModuleHostOptions { catalogSource = new DotNetAssemblyCatalogSource(typeof(DynamicModalTests).Assembly) }); + m_types = new TypeCatalog(m_modules, new ReflectionTypeCatalogSource()); + m_runtime = new ImGuiEditorRuntime(new EditorContext(m_root, new EditorKeyboardPolicy(KeyModifier.Control, "Ctrl")), + m_types, m_logs, [state]); + m_runtime.Start(); + } + + internal void Refresh() => m_types.Rebuild(); + + internal void Frame() + { + NativeGui.Raw.SetCurrentContext(m_native); + m_runtime.PrepareFrame(); + NativeGui.NewFrame(); + m_runtime.Draw(); + state.popupOpen = NativeGui.IsPopupOpen("Dynamic Modal##tests.dynamic-modal"); + NativeGui.Render(); + } + + public void Dispose() + { + NativeGui.Raw.SetCurrentContext(m_native); + m_runtime.Dispose(); + m_types.Dispose(); + m_modules.Dispose(); + m_logs.Dispose(); + NativeGui.Raw.DestroyContext(m_native); + Directory.Delete(m_root, true); + } + } +} + +public sealed class DynamicModalState +{ + public string message = "Short"; + public float zoom = 1f; + public bool showAction = true; + public bool showProgress = true; + public bool indeterminate; + public string? details; + public Vector2 initialSize; + public bool resizable; + public bool visible = true; + public bool rejectPreparation; + public bool rejectDraw; + public bool canceled; + public int actions; + public bool popupOpen; + public Vector2 actionMin; + public float scrollMaxX; + public float wrapWidth; + public float bodyHeight; + public float bodyContentHeight; + public int preparations; + public int draws; + public DialogPresentation content; + public DialogLayout layout; + public Vector2 windowSize; + public Vector2 windowMax; + public Vector2 actionMax; +} + +[EditorModal("tests.dynamic-modal", "Dynamic Modal")] +public sealed unsafe class DynamicTestModal(DynamicModalState state) : EditorModal +{ + public override bool isVisible => state.visible; + public override bool allowScrolling => false; + public override Vector2 initialSize => state.initialSize; + public override bool canResize => state.resizable; + protected override Vector2? OnPrepare( + EditorContext context, + Vector2 availableContentSize + ) { + state.preparations++; + if (state.rejectPreparation) throw new InvalidOperationException("Rejected modal measurement."); + EditorUiSession.current.widgets.style.SetZoom(state.zoom); + state.content = new(state.message, state.showProgress ? 0.5f : null, state.indeterminate, + actionLabel: state.showAction ? "Cancel" : null, actionEnabled: !state.canceled, details: state.details, cancelOnEscape: true); + state.layout = EditorUiSession.current.widgets.MeasureDialog(state.content, availableContentSize); + return state.layout.size; + } + + protected override void OnDraw(EditorContext context) + { + state.draws++; + state.windowSize = NativeGui.GetWindowSize(); + state.windowMax = NativeGui.GetWindowPos() + state.windowSize; + if (EditorUiSession.current.widgets.DrawDialog(state.content, state.layout)) + { + state.actions++; + state.canceled = true; + } + state.actionMin = NativeGui.GetItemRectMin(); + state.scrollMaxX = NativeGui.GetScrollMaxX(); + var window = NativeGui.Raw.GetCurrentWindow(); + state.wrapWidth = NativeGui.GetContentRegionAvail().X; + state.bodyHeight = state.message.Length == 0 ? 0f : NativeGui.CalcTextSize(state.message, false, state.wrapWidth).Y; + state.bodyContentHeight = state.bodyHeight; + if (window->DC.ChildWindows.Size > 0) + { + var child = window->DC.ChildWindows.Data[0]; + state.wrapWidth = child->WorkRect.Max.X - child->WorkRect.Min.X; + state.bodyHeight = child->Size.Y; + state.bodyContentHeight = child->ContentSize.Y; + } + if (state.rejectDraw) throw new InvalidOperationException("Rejected modal drawing."); + state.actionMax = NativeGui.GetItemRectMax(); + } +} diff --git a/tests/editor/Inno.Editor.PlayMode.Tests/EditorPlayModeTests.cs b/tests/editor/Inno.Editor.PlayMode.Tests/EditorPlayModeTests.cs index 51b07915..c673db7e 100644 --- a/tests/editor/Inno.Editor.PlayMode.Tests/EditorPlayModeTests.cs +++ b/tests/editor/Inno.Editor.PlayMode.Tests/EditorPlayModeTests.cs @@ -549,9 +549,9 @@ public void Dispose() private sealed class FakeScriptCompilation(EditorScriptCompilationState initialState) : IEditorScriptCompilation { public bool requiresExclusiveProgress => false; - public float progress => 0f; + public EditorScriptCompilationProgress progress => new(0, 0f, "Test script status.", false); - public void CancelCompilation() + public void CancelCompilation(long operationId) { } @@ -576,7 +576,6 @@ public EditorScriptCompilationState state } } - public string status => "Test script status."; public ScriptCompilationResult? lastCompilation => null; } diff --git a/tests/scripting/Inno.Editor.Scripting.Tests/ScriptingPipelineTests.Progress.cs b/tests/scripting/Inno.Editor.Scripting.Tests/ScriptingPipelineTests.Progress.cs new file mode 100644 index 00000000..29180f7d --- /dev/null +++ b/tests/scripting/Inno.Editor.Scripting.Tests/ScriptingPipelineTests.Progress.cs @@ -0,0 +1,55 @@ +using System.Threading.Tasks; +using Inno.Scripting.Compiler; +using Inno.Scripting.Reload; +using Xunit; + +namespace Inno.Editor.Scripting.Tests; + +public sealed partial class ScriptingPipelineTests +{ + [Fact] + [Trait("ProcessIsolation", "Required")] + public void SupersededCompilationCannotPublishIntoTheNextProgressOperation() + { + m_fixture.Write("Progress.cs", "public sealed class ProgressPayload { }"); + using ScriptReloadHost reload = m_fixture.CreateReloadHost(); + reload.Start(); + reload.RecompileScripting(); + ScriptReloadProgress first = reload.progress; + Assert.True(reload.TryCompilePending(out Task? running)); + reload.RecompileScripting(); + ScriptReloadProgress queued = reload.progress; + Assert.True(queued.operationId > first.operationId); + Assert.False(reload.CancelCompilation(first.operationId)); + _ = CompleteCompilationOnOwner(running!); + Assert.Same(queued, reload.progress); + Assert.Equal(0f, queued.fraction); + Assert.Contains("queued", queued.stage); + Assert.False(queued.canCancel); + Assert.True(reload.TryCompilePending(out Task? replacement)); + Assert.True(CompleteCompilationOnOwner(replacement!).success); + ScriptReloadProgress compiled = reload.progress; + Assert.Equal(queued.operationId, compiled.operationId); + Assert.Equal(0.8f, compiled.fraction); + Assert.Contains("waiting for generation activation", compiled.stage); + Assert.False(compiled.canCancel); + Assert.Equal(0f, queued.fraction); + } + + [Fact] + [Trait("ProcessIsolation", "Required")] + public void CompilationFailureDoesNotPublishSuccessfulWorkflowCompletion() + { + m_fixture.Write("InvalidProgress.cs", "public sealed class Broken {"); + using ScriptReloadHost reload = m_fixture.CreateReloadHost(); + reload.Start(); + ScriptCompilationResult result = m_fixture.CompilePending(reload); + Assert.False(result.success); + Assert.Contains("failed", reload.progress.stage); + Assert.False(reload.progress.canCancel); + Assert.False(reload.progress.cancellationRequested); + } + + // Reload and fixture retirement must remain on their creating owner thread. + private static ScriptCompilationResult CompleteCompilationOnOwner(Task compilation) => compilation.GetAwaiter().GetResult(); +} diff --git a/tests/scripting/Inno.Editor.Scripting.Tests/ScriptingPipelineTests.cs b/tests/scripting/Inno.Editor.Scripting.Tests/ScriptingPipelineTests.cs index c1abee2b..715e1440 100644 --- a/tests/scripting/Inno.Editor.Scripting.Tests/ScriptingPipelineTests.cs +++ b/tests/scripting/Inno.Editor.Scripting.Tests/ScriptingPipelineTests.cs @@ -950,7 +950,7 @@ public void EditorSampleImportUsesSharedModalAndUndoRedo() using EditorInteractionRuntime runtime = fixture.CreateEditorRuntime(); runtime.Start(); IEditorScriptCompilation scripting = Assert.IsAssignableFrom(ScriptingCompilationProbe.compilation); - PumpEditorUntil(fixture, runtime, () => scripting.state == EditorScriptCompilationState.Ready, () => scripting.status); + PumpEditorUntil(fixture, runtime, () => scripting.state == EditorScriptCompilationState.Ready, () => scripting.progress.status); Assert.True(fixture.assets.TryGetFileSystemEntry(new AssetPath(new AssetSourceId("tests.samples"), "~Starter"), out AssetFileEntry sample)); Assert.True(runtime.interactions.For("panel/asset.file-browser", sample).Execute("file-browser/import-sample")); EditorModalExtension modal = runtime.modals.Single(value => value.id == "asset-sample-import.progress"); @@ -961,7 +961,7 @@ public void EditorSampleImportUsesSharedModalAndUndoRedo() EditorModalExtension compilationModal = runtime.modals.Single(value => value.id == "scripting.compilation"); Assert.True(compilationModal.TryGetPresentation(out EditorModalExtension.Presentation compilationPolicy)); Assert.Equal(compilationPolicy.allowScrolling, presentation.allowScrolling); - PumpEditorUntil(fixture, runtime, () => modal.TryGetPresentation(out EditorModalExtension.Presentation state) && !state.isVisible, () => scripting.status); + PumpEditorUntil(fixture, runtime, () => modal.TryGetPresentation(out EditorModalExtension.Presentation state) && !state.isVisible, () => scripting.progress.status); Assert.True(fixture.assets.TryGetFileSystemEntry(AssetPath.Project("~Starter"), out _)); Assert.True(runtime.interactions.history.Undo().succeeded); Assert.False(fixture.assets.TryGetFileSystemEntry(AssetPath.Project("~Starter"), out _)); @@ -976,7 +976,7 @@ public void SampleTransformRunsOnWorkerAndEditorStopRetainsPendingImport() using EditorInteractionRuntime runtime = fixture.CreateEditorRuntime(); runtime.Start(); IEditorScriptCompilation scripting = Assert.IsAssignableFrom(ScriptingCompilationProbe.compilation); - PumpEditorUntil(fixture, runtime, () => scripting.state == EditorScriptCompilationState.Ready, () => scripting.status); + PumpEditorUntil(fixture, runtime, () => scripting.state == EditorScriptCompilationState.Ready, () => scripting.progress.status); using var control = new ControlledSampleSourceRewriter.Control(); ControlledSampleSourceRewriter.current = control; try @@ -1753,7 +1753,7 @@ public void EditorAutomaticCompilationClosesModalAndTicketWaitsForRetirement() using EditorInteractionRuntime runtime = m_fixture.CreateEditorRuntime(); runtime.Start(); IEditorScriptCompilation scripting = Assert.IsAssignableFrom(ScriptingCompilationProbe.compilation); - PumpEditorUntil(m_fixture, runtime, () => scripting.state == EditorScriptCompilationState.Ready, () => scripting.status); + PumpEditorUntil(m_fixture, runtime, () => scripting.state == EditorScriptCompilationState.Ready, () => scripting.progress.status); AssertCompilationModalHidden(runtime); ScriptCompilationResult initial = Assert.IsType(scripting.lastCompilation); for (int frame = 0; frame < 150; frame++) @@ -1770,13 +1770,13 @@ public void EditorAutomaticCompilationClosesModalAndTicketWaitsForRetirement() m_fixture.WriteVersionedBehavior(2); m_fixture.Rescan(); IScriptCompilationTicket ticket = scripting.RequestCompilation(); - PumpEditorUntil(m_fixture, runtime, () => m_fixture.host.modules.generations.state == GenerationState.AwaitingCollection, () => scripting.status); + PumpEditorUntil(m_fixture, runtime, () => m_fixture.host.modules.generations.state == GenerationState.AwaitingCollection, () => scripting.progress.status); Assert.Equal(ScriptCompilationTicketState.Compiling, ticket.state); Assert.False(ticket.isCompleted); retained.Clear(); // Publication readiness may be advanced by another host boundary before the next editor update. m_fixture.host.modules.generations.Wait(); - PumpEditorUntil(m_fixture, runtime, () => scripting.state == EditorScriptCompilationState.Ready && ticket.isCompleted, () => scripting.status, focused: false); + PumpEditorUntil(m_fixture, runtime, () => scripting.state == EditorScriptCompilationState.Ready && ticket.isCompleted, () => scripting.progress.status, focused: false); Assert.Equal(ScriptCompilationTicketState.Succeeded, ticket.state); AssertCompilationModalHidden(runtime); Assert.Equal(2, ReadVersion(m_fixture.ResolveActiveType("VersionedBehavior"))); @@ -1801,7 +1801,7 @@ public void EditorQueuesLatestAutomaticChangeWithoutReplacingAcceptedTicketWhile fixture, runtime, () => scripting.state == EditorScriptCompilationState.Ready, - () => $"{scripting.state}: {scripting.status}; ticket={scripting.currentTicket?.state}", + () => $"{scripting.state}: {scripting.progress.status}; ticket={scripting.currentTicket?.state}", timeoutMilliseconds: 120000 ); ScriptCompilationResult initial = Assert.IsType(scripting.lastCompilation); @@ -1826,7 +1826,7 @@ public void EditorQueuesLatestAutomaticChangeWithoutReplacingAcceptedTicketWhile Assert.Same(initial, scripting.lastCompilation); Assert.Same(accepted, scripting.currentTicket); - Assert.Contains("fixture active Play", scripting.status); + Assert.Contains("fixture active Play", scripting.progress.status); AssertCompilationModalHidden(runtime); } @@ -1835,7 +1835,7 @@ public void EditorQueuesLatestAutomaticChangeWithoutReplacingAcceptedTicketWhile fixture, runtime, () => scripting.state == EditorScriptCompilationState.Ready && !ReferenceEquals(initial, scripting.lastCompilation), - () => $"{scripting.state}: {scripting.status}; ticket={scripting.currentTicket?.state}", + () => $"{scripting.state}: {scripting.progress.status}; ticket={scripting.currentTicket?.state}", timeoutMilliseconds: 120000 ); Assert.Equal(GenerationState.Ready, fixture.host.generations.state); @@ -2265,9 +2265,9 @@ public void Dispose() private sealed class ReadyScriptCompilation : IEditorScriptCompilation { public bool requiresExclusiveProgress => false; - public float progress => 0f; + public EditorScriptCompilationProgress progress => new(0, 0f, "Test script status.", false); - public void CancelCompilation() + public void CancelCompilation(long operationId) { } @@ -2275,7 +2275,6 @@ public void CancelCompilation() public IScriptCompilationTicket RequestCompilation() => m_ticket; public IScriptCompilationTicket? currentTicket => m_ticket; public EditorScriptCompilationState state => EditorScriptCompilationState.Ready; - public string status => "The test script generation is ready."; public ScriptCompilationResult? lastCompilation => null; private sealed class ReadyCompilationTicket : IScriptCompilationTicket diff --git a/tests/scripting/Inno.Editor.Scripting.Tests/ShaderEditorWorkflowTests.cs b/tests/scripting/Inno.Editor.Scripting.Tests/ShaderEditorWorkflowTests.cs index 388871b6..ebbd255f 100644 --- a/tests/scripting/Inno.Editor.Scripting.Tests/ShaderEditorWorkflowTests.cs +++ b/tests/scripting/Inno.Editor.Scripting.Tests/ShaderEditorWorkflowTests.cs @@ -179,6 +179,7 @@ public unsafe void DiagnosticCheckUsesTheStandardTransientModalWithoutChangingFi _ = ImGuiApi.Raw.Begin((sbyte*)nativeTestText0.pointer, null, 0); try { + Assert.True(modal.TryPrepare(m_runtime.context, presentation, new Vector2(1100, 700), out _)); Assert.True(modal.Draw(m_runtime.context)); } finally @@ -187,6 +188,7 @@ public unsafe void DiagnosticCheckUsesTheStandardTransientModalWithoutChangingFi ImGuiApi.Render(); } + m_runtime.Update(new EditorFrame(0.01f, frame * 0.01f, true)); Thread.Sleep(5); Assert.True(modal.TryGetPresentation(out presentation)); }