refactor(settings): a pull-out drawer, with Zoom as a category — and the menu moves to the wordmark

Creator directive, 2026-11-01. Settings stopped being a centred modal.

- **Drawer** (Controls/SettingsDrawer): hosted in PreviewPane's pull-out stack, 320px, the same
  animated-width pattern as Stream Settings / YPP / Socials / TEST, opened by the gear rail tab
  on a single left click. SettingsDrawerOpen is exclusive with the other four, both directions.
  This also removes the modal's MaxHeight-700 scroll problem for good: the drawer is the height
  of the preview.
- **Categories**: headings with controls indented beneath them. Zoom now owns *Zoom view shape*
  (Circle / Phone / Tablet) and *Zoom box follows*; Recordings, Brand logo and Scene transition
  are their own categories.
- **The app menu moved to the LlamaCasty wordmark** (right-click → Report Bug / Feature Request /
  About). Left-click still opens About. The gear tab no longer carries a menu at all, so clicking
  it does exactly one thing.

OverlayHost keeps only the Bug / Feature / About panels; its brand-logo handlers and the dev-panel
injection moved with the settings block. BrandLogoPreviewTests follows the control (same assertions,
new path). Release 0 warnings; 15 tests pass across brand logo, zoom, entitlement and preview
history.
This commit is contained in:
2026-11-01 09:16:27 -08:00
parent c418288215
commit a35ec0c5f8
14 changed files with 310 additions and 173 deletions
+58
View File
@@ -0,0 +1,58 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace ytLive.Controls;
/// <summary>
/// App Settings as a right-edge pull-out (creator ruling 2026-11-01). Hosted by
/// <see cref="PreviewPane"/>'s drawer stack and opened by the gear rail tab, exactly like Stream
/// Settings / YPP / Socials / TEST.
///
/// <para>Born from the modal overlay: that shell was MaxHeight 700, so once the section list grew
/// the bottom options were clipped and unreachable — including the zoom shape the creator was
/// looking for. A drawer is the height of the preview, so the list can grow without a second
/// scroll decision to get wrong.</para>
/// </summary>
public partial class SettingsDrawer : UserControl
{
public SettingsDrawer()
{
InitializeComponent();
#if DEBUG
// Development affordances are added at runtime, never declared in XAML: the panel is
// excluded from the Release compile (ytLive.csproj), so this line is the only reference.
DeveloperPanelHost.Children.Add(new DeveloperPanel());
#endif
}
/// <summary>Is the enlarged brand-logo preview showing? Test seam — a Popup is a separate
/// window, so nothing else can observe it.</summary>
internal bool IsBrandLogoPreviewOpen => BrandLogoPreviewPopup.IsOpen;
/// <summary>The thumbnail is hidden when no image is set (see the XAML), so there is nothing to
/// open in that case — no empty frame can appear.</summary>
internal void OpenBrandLogoPreview() => BrandLogoPreviewPopup.IsOpen = true;
internal void CloseBrandLogoPreview() => BrandLogoPreviewPopup.IsOpen = false;
/// <summary>Hover opens the enlargement. Nothing to show when no image is set, so the
/// thumbnail simply does nothing in that case.</summary>
private void BrandLogoThumb_MouseEnter(object sender, MouseEventArgs e)
=> BrandLogoPreviewPopup.IsOpen = true;
/// <summary>Leaving the thumbnail closes it — unless the pointer walked onto the popup
/// itself, where it stays put so the creator can look closely.</summary>
private void BrandLogoThumb_MouseLeave(object sender, MouseEventArgs e)
{
if (BrandLogoPreviewPopup.Child?.IsMouseOver == true) return;
BrandLogoPreviewPopup.IsOpen = false;
}
/// <summary>A click collapses the enlargement — the explicit "enough, thanks" gesture.</summary>
private void BrandLogoThumb_Click(object sender, MouseButtonEventArgs e)
=> BrandLogoPreviewPopup.IsOpen = false;
private void BrandLogoPreviewPopup_MouseLeave(object sender, MouseEventArgs e)
=> BrandLogoPreviewPopup.IsOpen = false;
}