mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-08-17 17:31:44 +08:00
Update copilot prompts
This commit is contained in:
@@ -0,0 +1,218 @@
|
||||
# Layout and GuiGraphicsComposition (Core Layout & Responsive Families)
|
||||
|
||||
## 1. Scope & Purpose
|
||||
This document explains the GacUI layout architecture centered on `GuiGraphicsComposition` and its classification subclasses, the predefined layout container families, bidirectional constraint propagation, invalidation & recomputation workflow driven by `GuiGraphicsHost::Render`, extension guidelines, and the responsive ("reactive") composition family (`GuiResponsive*`). It consolidates prior Q&A insights into a coherent design reference for future maintenance and extension.
|
||||
|
||||
## 2. Core Abstractions
|
||||
### 2.1 Base Class: `GuiGraphicsComposition`
|
||||
Responsibilities:
|
||||
- Maintain hierarchy: `children`, `parent` (mutation via `InsertChild`, `RemoveChild`, `MoveChild`).
|
||||
- Own a single graphics element: `ownedElement` (setter `SetOwnedElement`).
|
||||
- Store presentation & interaction flags: `visible`, `transparentToMouse`.
|
||||
- Store layout configuration: `internalMargin`, `preferredMinSize`, `minSizeLimitation`.
|
||||
- Cache measurement: `cachedMinSize` (set only by `Layout_SetCachedMinSize`), and arrangement: `cachedBounds` (set only by `Layout_SetCachedBounds`).
|
||||
- Propagate host context: `relatedHostRecord` via `UpdateRelatedHostRecord`.
|
||||
- Provide virtual layout interface:
|
||||
* `Layout_CalculateMinSize()` (measurement)
|
||||
* `Layout_CalculateMinClientSizeForParent(Margin parentInternalMargin)` (child -> parent contribution)
|
||||
* `Layout_CalculateBounds(Size parentSize)` (arrangement)
|
||||
- Orchestrate recursive layout passes via helpers:
|
||||
* `Layout_UpdateMinSize()` (calls overridden min size function then caches and fires `CachedMinSizeChanged`).
|
||||
* `Layout_UpdateBounds(Size parentSize)` (computes own bounds then recurses to children).
|
||||
* `Layout_CalculateMinSizeHelper()` shared policy used by most containers.
|
||||
- Invalidation trigger: `InvokeOnCompositionStateChanged(forceRequestRender)` sets flags; does not directly perform layout.
|
||||
- Synchronous optional recompute: `ForceCalculateSizeImmediately()` (used sparingly, e.g., interactive splitters).
|
||||
- Rendering entry: `Render` consumes only `cachedBounds` (no layout recalculation inside rendering).
|
||||
|
||||
### 2.2 Classification Subclasses
|
||||
Purpose: Distinguish measurement & arrangement control patterns.
|
||||
1. `GuiGraphicsComposition_Trivial`
|
||||
- Container autonomously computes measurement and bounds using standard algorithm (often via `Layout_CalculateMinSizeHelper`).
|
||||
- Examples: `GuiBoundsComposition`, `GuiTableComposition`, `GuiStackComposition`, `GuiFlowComposition`, `GuiSharedSizeRootComposition` (directly or indirectly).
|
||||
2. `GuiGraphicsComposition_Controlled`
|
||||
- Measurement / bounds set externally by parent; overrides `Layout_CalculateMinSize` & `Layout_CalculateBounds` to simply return cached values (no internal recompute). Parent writes caches using specialized setters (e.g., `GuiCellComposition::Layout_SetCellBounds`, `GuiStackItemComposition::Layout_SetStackItemBounds`, `GuiFlowItemComposition::Layout_SetFlowItemBounds`).
|
||||
- Typical for helper items: `GuiCellComposition`, splitters, stack items, flow items, shared size items.
|
||||
3. `GuiGraphicsComposition_Specialized`
|
||||
- Container with custom arrangement while limiting child -> parent enlargement; usually still uses `Layout_CalculateMinSizeHelper` but overrides `Layout_CalculateMinClientSizeForParent` to `{0,0}`.
|
||||
- Examples: `GuiSideAlignedComposition`, `GuiPartialViewComposition`, `GuiWindowComposition`.
|
||||
|
||||
## 3. Layout Pass Orchestration
|
||||
### 3.1 Measurement Flow
|
||||
`Layout_UpdateMinSize()` executes:
|
||||
1. Calls overridden `Layout_CalculateMinSize()`.
|
||||
2. That implementation typically delegates to `Layout_CalculateMinSizeHelper()`:
|
||||
- Start from `preferredMinSize`.
|
||||
- If `minSizeLimitation != NoLimit`, merge element renderer minimum.
|
||||
- Add `internalMargin`.
|
||||
- For each child: `child->Layout_UpdateMinSize()`.
|
||||
- If own `minSizeLimitation == LimitToElementAndChildren`, incorporate each child's contribution via `child->Layout_CalculateMinClientSizeForParent(internalMargin)`.
|
||||
3. Result stored by `Layout_SetCachedMinSize()` raising `CachedMinSizeChanged` for observers (parents, containers, special logic like stack/table invalidation flags).
|
||||
|
||||
### 3.2 Arrangement Flow
|
||||
`Layout_UpdateBounds(parentSize)` executes:
|
||||
1. Compute own rectangle with overridden `Layout_CalculateBounds(parentSize)`, store via `Layout_SetCachedBounds`.
|
||||
2. For each child: call `child->Layout_UpdateBounds(ownSize)`.
|
||||
3. Controlled children rely on parent precomputed rectangles delivered via container-specific setters instead of independent calculation.
|
||||
|
||||
### 3.3 Host-Driven Iteration
|
||||
- Changes call `InvokeOnCompositionStateChanged()` marking layout invalid (and optionally requesting a render).
|
||||
- `GuiGraphicsHost::Render` loops: if any layout-invalid flag is set for the window root subtree, perform a full layout (measurement + arrangement cascade), then render. Repeats until no invalidation remains.
|
||||
- Ensures deterministic stabilization without requiring synchronous recalculation inside property setters.
|
||||
- `ForceCalculateSizeImmediately()` is an optimization for immediate feedback inside event handlers (e.g., splitter dragging) but never required for correctness.
|
||||
|
||||
## 4. Invalidation Sources & Flags
|
||||
### 4.1 Generic Triggers
|
||||
- Structural: `InsertChild`, `RemoveChild`, `MoveChild`.
|
||||
- Property mutations: `SetInternalMargin`, `SetPreferredMinSize`, `SetVisible`, `SetMinSizeLimitation`, alignment & anchor changes.
|
||||
- Element replacement: `SetOwnedElement`.
|
||||
|
||||
### 4.2 Container-Specific Triggers
|
||||
- Table: `SetRowOption`, `SetColumnOption`, `SetCellPadding`, `SetBorderVisible`, `SetRowsAndColumns` (set `layout_invalid`, `layout_invalidCellBounds`).
|
||||
- Stack: `SetDirection`, `SetPadding`, scroll / ensure visible logic (sets `layout_invalid`).
|
||||
- Flow: `SetAxis`, `SetRowPadding`, other adjustments setting `layout_invalid`.
|
||||
- SharedSizeRoot: any group membership changes or measuring resets dictionaries.
|
||||
- Splitters: mouse move adjusting adjacent option values then invalidating parent + optional immediate recompute.
|
||||
- Responsive (later section): level transitions call `InvokeOnCompositionStateChanged` at root responsive node.
|
||||
|
||||
### 4.3 Child-Originated Propagation
|
||||
- Container listens to children `CachedMinSizeChanged` to raise its own invalidation flags (e.g., table cell, stack item, flow item compositions) to recompute aggregated geometry lazily on next layout pass.
|
||||
|
||||
## 5. Bidirectional Constraints
|
||||
### 5.1 Parent -> Child Constraint
|
||||
- Parent supplies available size during `Layout_UpdateBounds` recursion.
|
||||
- Specialized containers compute per-child rectangles first (table grid, stack linear offsets, flow line wrapping) then assign them (especially controlled children) using internal `Layout_Set...Bounds` helpers.
|
||||
|
||||
### 5.2 Child -> Parent Constraint
|
||||
- During parent measurement, after calling each child's `Layout_UpdateMinSize`, parent optionally adds `child->Layout_CalculateMinClientSizeForParent(internalMargin)` to its accumulated client size if own `minSizeLimitation == LimitToElementAndChildren`.
|
||||
- Controlled children often contribute `{0,0}` because parent already manually accounts for them (e.g., table computing row/column sizes; stack computing cumulative lengths; flow computing wrapping layout).
|
||||
|
||||
## 6. Predefined Layout Families
|
||||
Distinct algorithms (excluding helper-only controlled items):
|
||||
1. Bounds: `GuiBoundsComposition` (absolute rectangle + `alignmentToParent`).
|
||||
2. Table: `GuiTableComposition` (mixed absolute / percentage / min, spanning, splitters via `GuiRowSplitterComposition`, `GuiColumnSplitterComposition`).
|
||||
3. Stack: `GuiStackComposition` (directional linear, reversed variants, ensure-visible virtualization support via internal offset logic).
|
||||
4. Flow: `GuiFlowComposition` (adaptive multi-row wrapping with `FlowAlignment` & `GuiFlowOption` baseline/alignment choices).
|
||||
5. Shared Size: `GuiSharedSizeRootComposition` (cross-subtree size normalization for named groups via per-dimension dictionaries; item: `GuiSharedSizeItemComposition`).
|
||||
6. Side Aligned: `GuiSideAlignedComposition` (dock to a specified side with length ratio / max constraints).
|
||||
7. Partial View: `GuiPartialViewComposition` (scroll / viewport style fractional sub-rectangle selection with offsets).
|
||||
8. Window Root: `GuiWindowComposition` (ties client area to native window size, root for layout passes).
|
||||
Helper controlled participants: `GuiCellComposition`, `GuiStackItemComposition`, `GuiFlowItemComposition`, `GuiSharedSizeItemComposition`, `GuiRowSplitterComposition`, `GuiColumnSplitterComposition`.
|
||||
|
||||
## 7. Internal Optimization Flags & Lazy Strategies
|
||||
- Table maintains `layout_invalid`, `layout_invalidCellBounds`, recalculating row/column metrics and cell rectangles only when flagged inside `Layout_CalculateMinSize` / `Layout_CalculateBounds` (helpers: `Layout_UpdateCellBoundsInternal`, `Layout_UpdateCellBoundsPercentages`, `Layout_UpdateCellBoundsOffsets`).
|
||||
- Stack uses `layout_invalid`; recalculations centralized in `Layout_UpdateStackItemMinSizes` and arrangement in `Layout_UpdateStackItemBounds`.
|
||||
- Flow uses `layout_invalid` plus last constraint width; layout regeneration in `Layout_UpdateFlowItemLayout` / `Layout_UpdateFlowItemLayoutByConstraint`.
|
||||
- Shared Size re-derives `CalculateOriginalMinSizes`, `CollectSizes`, `AlignSizes` each pass (group dictionary rebuild).
|
||||
- Responsive container (later) recalculates bounds iteratively while adjusting levels.
|
||||
|
||||
## 8. Responsive (Reactive) Composition Family
|
||||
### 8.1 Goals
|
||||
Add adaptive multi-level representations (compact to expanded) without duplicating control state, layering on top of existing layout passes and invalidation system.
|
||||
|
||||
### 8.2 Key Classes
|
||||
- Abstract: `GuiResponsiveCompositionBase` (inherits `GuiBoundsComposition`).
|
||||
- Strategy / aggregator:
|
||||
* `GuiResponsiveViewComposition` (collection of alternative view subtrees + shared control migration).
|
||||
* `GuiResponsiveStackComposition` (summation-based level aggregation; adjust one child per level change).
|
||||
* `GuiResponsiveGroupComposition` (max-based aggregation; synchronized level propagation across children).
|
||||
* `GuiResponsiveFixedComposition` (terminal level 0 node).
|
||||
* `GuiResponsiveSharedComposition` (placeholder that installs a control from view's `sharedControls`).
|
||||
* `GuiResponsiveContainerComposition` (auto-resizes target by dynamic LevelUp/LevelDown based on live size comparisons).
|
||||
|
||||
### 8.3 Level Model & Operations
|
||||
- Each responsive subtree exposes `GetLevelCount()` and `GetCurrentLevel()`.
|
||||
- Transition methods: `LevelUp()`, `LevelDown()` return bool (true if level changed) enabling parent fallbacks.
|
||||
- `GuiResponsiveViewComposition` maintains `currentView` pointer; switching occurs only when leaf view can't further down/up inside itself (delegation to child fails) then advances to next/previous view; fires `BeforeSwitchingView` event before installing new view child.
|
||||
- Aggregation formulas:
|
||||
* View: `levelCount` = ?(child.levelCount or 1 if direction mismatch); `currentLevel` computed by reverse accumulation.
|
||||
* Stack: `levelCount` = ?(children.levelCount - 1) + 1; `currentLevel` = ?(children.currentLevel); change selects best candidate child by size heuristic.
|
||||
* Group: `levelCount` = max(children.levelCount); `currentLevel` = max(children.currentLevel); change broadcasts attempts.
|
||||
* Fixed: constants (1,0).
|
||||
|
||||
### 8.4 Direction Filtering
|
||||
- Each node has `ResponsiveDirection direction` mask; only children whose direction overlaps (`child->GetDirection()`) participate in counts & changes (macro-assisted filtering in Stack/Group code).
|
||||
|
||||
### 8.5 Shared Control Migration
|
||||
- `GuiResponsiveSharedComposition` locates ancestor `GuiResponsiveViewComposition` in `OnParentLineChanged` and installs its designated shared control (validated membership in `sharedControls`).
|
||||
- On view switch: old subtree removed, new view added, placeholders reinstall matching shared controls preserving internal widget state.
|
||||
|
||||
### 8.6 Automatic Adaptive Wrapper
|
||||
- `GuiResponsiveContainerComposition` monitors actual bounds vs `minSizeLowerBound` / `minSizeUpperBound`.
|
||||
- If shrinking below lower bound: loop `Layout_AdjustLevelDown` (calls target `LevelDown` + remeasure until fits or minimal).
|
||||
- If expanding beyond upper bound: loop `Layout_AdjustLevelUp` (speculative raise then rollback if overshoot) using `Layout_CompareSize` to test width/height axes indicated by direction bits.
|
||||
- After each level change, invokes `responsiveTarget->Layout_UpdateMinSize()` to refresh bounds used for subsequent comparisons.
|
||||
|
||||
### 8.7 Invalidation & Events
|
||||
- Any level recalculation culminating at root triggers `InvokeOnCompositionStateChanged` (root determined when `responsiveParent == nullptr`).
|
||||
- Events: `LevelCountChanged`, `CurrentLevelChanged` emitted only on value change; `BeforeSwitchingView` emitted just prior to replacing the active view child.
|
||||
|
||||
### 8.8 Extension Guidelines (Responsive)
|
||||
- Subclass `GuiResponsiveCompositionBase`.
|
||||
- Implement level introspection and transitions (`GetLevelCount`, `GetCurrentLevel`, `LevelUp`, `LevelDown`).
|
||||
- Maintain internal child collections with insertion/removal hooks (`OnResponsiveChildInserted/Removed`) if aggregating.
|
||||
- Propagate recalculation upward via `OnResponsiveChildLevelUpdated` after recomputing own counts.
|
||||
- Apply direction filtering semantics uniformly (mask intersection tests).
|
||||
|
||||
## 9. Detailed Constraint Examples
|
||||
### 9.1 Table Example (Column Percentage Change)
|
||||
1. Setter `GuiTableComposition::SetColumnOption` updates model then calls `InvokeOnCompositionStateChanged()`.
|
||||
2. Next `GuiGraphicsHost::Render` detects invalid layout, triggers full window layout.
|
||||
3. Table `Layout_CalculateMinSize` sees `layout_invalid` -> recomputes metrics; `Layout_CalculateBounds` updates each `GuiCellComposition` via `Layout_SetCellBounds`.
|
||||
4. Rendering consumes new `cachedBounds`.
|
||||
|
||||
### 9.2 Interactive Splitter Drag
|
||||
1. Mouse move updates adjacent Absolute options.
|
||||
2. Each option setter invalidates table.
|
||||
3. Drag handler optionally calls `ForceCalculateSizeImmediately()` for immediate geometry update (without waiting for host loop) to achieve fluid cursor feedback.
|
||||
|
||||
## 10. Adding a New Layout Composition (Non-Responsive)
|
||||
Checklist:
|
||||
1. Choose subclass archetype (Trivial vs Specialized vs Controlled) based on whether parent or child owns measurement/arrangement logic.
|
||||
2. Define internal dirty flags mirroring existing patterns (e.g., `layout_invalid`).
|
||||
3. Implement measurement using either `Layout_CalculateMinSizeHelper()` or custom pass collecting controlled child min sizes first (as table/stack/flow do).
|
||||
4. Implement arrangement; for multi-phase (size distribution + placement) separate helpers and guard with dirty flags.
|
||||
5. Decide child -> parent influence by overriding `Layout_CalculateMinClientSizeForParent` (return `{0,0}` to suppress growth).
|
||||
6. Provide internal setters for controlled children to assign bounds then mark them (e.g., `Layout_SetXItemBounds`).
|
||||
7. Fire `InvokeOnCompositionStateChanged()` in every state-mutating setter.
|
||||
8. Subscribe to children `CachedMinSizeChanged` where dynamic re-aggregation is required.
|
||||
9. Use `ForceCalculateSizeImmediately()` only for real-time adjustments inside input handlers when latency matters.
|
||||
|
||||
## 11. Adding a New Responsive Strategy
|
||||
Steps:
|
||||
1. Subclass `GuiResponsiveCompositionBase`.
|
||||
2. Maintain children list & direction mask; filter by direction overlaps.
|
||||
3. Implement `GetLevelCount` / `GetCurrentLevel` with chosen aggregation formula.
|
||||
4. Implement `LevelDown` / `LevelUp` returning false when already at boundary (enabling parent fallback switching logic in view/stack/group containers).
|
||||
5. Invoke recalculation & root invalidation through `OnResponsiveChildLevelUpdated`.
|
||||
6. Integrate with container adaptation if needed (work with `GuiResponsiveContainerComposition`).
|
||||
7. Provide deterministic selection heuristics for partial adjustments (e.g., choose largest or smallest child) if not all children change simultaneously.
|
||||
|
||||
## 12. Separation of Concerns
|
||||
- Layout computation (measurement + arrangement) is strictly segregated from rendering (`Render` side-effect-free wrt layout state).
|
||||
- Invalidation is single entry (`InvokeOnCompositionStateChanged`) leaving scheduling & iteration to the host.
|
||||
- Responsive system layers on top without altering the base pass algorithm; it only manipulates subtree structure and min-size outputs between passes.
|
||||
|
||||
## 13. Reliability & Stability Patterns
|
||||
- Iterative host loop ensures eventual fixpoint when cascading invalidations occur (e.g., responsive level changes causing new size measurements).
|
||||
- Dirty flag + lazy recomputation prevents redundant heavy recomputations (especially table & flow geometry).
|
||||
- Controlled compositions decouple per-item geometry from measuring logic to simplify parent algorithms.
|
||||
|
||||
## 14. Proof Reference Index (Quick Lookup)
|
||||
- Invalidation Core: `GuiGraphicsComposition::InvokeOnCompositionStateChanged`.
|
||||
- Layout Core Helpers: `Layout_CalculateMinSizeHelper`, `Layout_UpdateMinSize`, `Layout_UpdateBounds`.
|
||||
- Forced Immediate Recompute: `ForceCalculateSizeImmediately`.
|
||||
- Table: `GuiTableComposition::{SetRowOption,SetColumnOption,Layout_CalculateMinSize,Layout_UpdateCellBoundsInternal,Layout_UpdateCellBoundsPercentages,Layout_UpdateCellBoundsOffsets}`, cell bounds setter `GuiCellComposition::Layout_SetCellBounds`.
|
||||
- Stack: `GuiStackComposition::{SetDirection,Layout_UpdateStackItemMinSizes,Layout_CalculateMinSize,Layout_UpdateStackItemBounds}`, item setter `GuiStackItemComposition::Layout_SetStackItemBounds`.
|
||||
- Flow: `GuiFlowComposition::{SetAxis,SetRowPadding,Layout_UpdateFlowItemLayout,Layout_UpdateFlowItemLayoutByConstraint}`, item setter `GuiFlowItemComposition::Layout_SetFlowItemBounds`.
|
||||
- Shared Size: `GuiSharedSizeRootComposition::{CalculateOriginalMinSizes,CollectSizes,AlignSizes}`, item logic `GuiSharedSizeItemComposition::Layout_CalculateMinSize`.
|
||||
- Splitters: `GuiTableSplitterCompositionBase::OnMouseMoveHelper`.
|
||||
- Responsive Base: `GuiResponsiveCompositionBase::{OnParentLineChanged,OnResponsiveChildLevelUpdated}`.
|
||||
- Responsive View: `GuiResponsiveViewComposition::{LevelDown,LevelUp,CalculateLevelCount,CalculateCurrentLevel}`.
|
||||
- Responsive Stack: `GuiResponsiveStackComposition::{CalculateLevelCount,CalculateCurrentLevel,LevelDown,LevelUp}`.
|
||||
- Responsive Group: `GuiResponsiveGroupComposition::{CalculateLevelCount,CalculateCurrentLevel,LevelDown,LevelUp}`.
|
||||
- Responsive Fixed: `GuiResponsiveFixedComposition` trivial implementations.
|
||||
- Responsive Shared: `GuiResponsiveSharedComposition::{OnParentLineChanged,SetSharedControl}`.
|
||||
- Responsive Container: `GuiResponsiveContainerComposition::{Layout_CalculateBounds,Layout_AdjustLevelUp,Layout_AdjustLevelDown,Layout_CompareSize}`.
|
||||
|
||||
## 15. Summary
|
||||
The GacUI layout engine employs a clean separation between invalidation, measurement, arrangement, and rendering, with composition classification enabling optimized parent-child cooperation patterns. Predefined container families cover common layout paradigms (grid, linear, wrapping, docking, viewport, shared sizing) while the responsive layer introduces adaptive multi-level UI transformation without complicating the core pass. Extension points are well-localized: new algorithms implement three virtual layout functions (or override contribution behavior), while responsive strategies implement discrete level semantics. Lazy flags and controlled item abstractions keep recomputation efficient, and host-driven iterative stabilization guarantees correctness even under cascading dynamic changes.
|
||||
Reference in New Issue
Block a user