From cb54637e9febd3f2b528762392c3f12e50052d14 Mon Sep 17 00:00:00 2001 From: gramps Date: Sun, 30 Aug 2026 21:41:18 -0700 Subject: [PATCH] =?UTF-8?q?docs:=20add=20Controls/index.md=20=E2=80=94=20t?= =?UTF-8?q?he=20missing=20per-directory=20map=20for=20Phase-2=20UserContro?= =?UTF-8?q?ls?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 2 (refactor-commit-12..18) created Controls/ with 6 UserControls that split MainWindow.xaml, but no index.md existed — a gap against the schema.md rule (one index.md per code directory). Documents each control, the window↔ control contract, and the Phase-2 landmines (window-resources converter rule, control xmlns, name-looked-up host stubs, dropped-Border). --- Controls/index.md | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 Controls/index.md diff --git a/Controls/index.md b/Controls/index.md new file mode 100644 index 0000000..6f2489d --- /dev/null +++ b/Controls/index.md @@ -0,0 +1,58 @@ +# Controls — index + +The phase-2 carved pieces of what used to be one monolithic `MainWindow.xaml` +(1,681 lines → a 123-line shell). Each is a `UserControl` in the `ytLive.Controls` +namespace, extracted one roll-back commit at a time (refactor-commit-12..18). +See [`schema.md`](../schema.md) for the memory-map conventions. + +| File | Purpose | +|------|---------| +| `BottomBar.xaml(.cs)` | Footer (Row 3): gear menu (stop/mic/game-mute/quality dropdown), stream stats (bitrate/fps/dropped/duration/health), resolution dropdown | +| `HealthBanner.xaml(.cs)` | Row 1 status banner + the 7 value→visibility converters live in the app theme, not here | +| `TopBar.xaml(.cs)` | Row 0 stream controls: REC/ON-AIR pills+signs, elapsed timer, start/stop, account avatar/name (`RefreshAvatar()`) | +| `PreviewPane.xaml(.cs)` | Row 1 Col 1 center: the 1920×1080 `OverlayCanvas`/`SelectionOverlay`/`BrandFlashLayer`/`SocialBarElement`, text pull-out drawer, and the live-controls row (TRAX / game / mic meters + sliders + speakers + socials) | +| `SceneThumbnailStrip.xaml(.cs)` | Row 0 scene-picker strip (`ItemsControl` over `Scenes`), staged-red / live-green border highlight | +| `LeftPanel.xaml(.cs)` | Row 1 Col 0 left panel: edit mode → layers+properties; live → YouTube chat. Source add/edit/remove, list drag-to-reorder, snapshot revert-accept | +| `OverlayHost.xaml(.cs)` | Root-grid overlay dialogs: Settings / Report Bug / Feature Request / About (+ licenses + license-key entry). `BackToAbout_Click` lives here | +| `SceneThumbnailStrip.xaml.cs` | Code-behind for the strip above | +| `LeftPanel.xaml.cs` | Code-behind for the panel above | + +## Window ↔ control contract + +The shell (`MainWindow.xaml(.cs)`) wires up each control and routes the few +cross-cutting calls through it: + +- Ctor finds each control by `x:Name` (`TopBar`, `PreviewPane`, `LeftPanel`) + AFTER `InitializeComponent`, **before** any method touches it (null-ref guard). +- `_previewPane.IsClickInsidePreview/Drawer` + `_leftPanel.IsClickInside` → + deselection guard in `Window_PreviewMouseLeftButtonDown`. +- `_previewPane.UpdateSelectionOverlay(bool)` + `_leftPanel.OnSelectionChanged(vm)` + → selection/edit-mode routing from the VM's `SelectedElement` change. +- `_topBar.RefreshAvatar()` on `IsConnected`/`AccountAvatarUrl` change. +- Handlers in moved controls cast `(DataContext as MainViewModel)` — controls + inherit the window's DataContext; never pass the VM through a property. + +## Gotchas learned the hard way + +- **A UserControl cannot see `Window.Resources`** (StaticResource resolves by + element lookup, so it stops at the control boundary). The 7 converters + (`BoolToVis`, `InverseBoolToVis`, `NotNullToVis`, `NullToVis`, `HiddenBoolToVis`, + `EnumToBool`, `AllTrueToVis`) were promoted from `MainWindow.Resources` into + `Themes/Controls.xaml` (see [`Themes/index.md`](../Themes/index.md)). +- **Moved XAML can lose its namespace**: a block cut from MainWindow carries no + root xmlns, so any `models:`/`Helpers:` ref in it breaks the build with + `MC2000: Value cannot be null (key)`. Declare `xmlns:models` / `xmlns:Helpers` + on each control's root (LeftPanel hit this). +- **Name-looked-up host stubs must stay in the window**, not a control: + `WebViewHostPanel` (ctor `InitWebView2(WebViewHostPanel)`) and `ToastArea` + (`NotificationService.InArea("ToastArea")`) are resolved by name from the + window root — so `OverlayHost` deliberately leaves them as thin window-root + children (Commit 18). +- When cutting visual wrappers, don't drop the outer `Border`'s + background/glow/margin — Commit 15 initially lost the preview's outer border + and had to restore it same-commit. + +Related: [`ViewModels/index.md`](../ViewModels/index.md) (MainViewModel the +controls bind to), [`Themes/index.md`](../Themes/index.md) (styles/converters), +[`Helpers/index.md`](../Helpers/index.md) (ViewModelBase, converters), the +`MainWindow.xaml` shell at repo root that hosts these.