fix(preview): Ctrl+right no longer opens the menu, and the social bar keeps its click
Two event-pairing bugs found by validating every handler instead of trusting the table. 1. Ctrl+right-click opened the context menu in edit mode. Cause: WPF's PopupControlService opens menus on right-button-UP, and only the DOWN event was being handled — so the zoom toggled and the menu appeared under it. Both events are now handled when Ctrl is down. (The creator saw this in edit mode; preview mode had the same latent bug.) 2. The social bar's left-click was dead in preview mode and dragged the layer beneath it in edit mode. Cause: PreviewGrid handles the TUNNELLING PreviewMouseLeftButtonDown, which fires before the bar's bubbling handler — and since preview-mode left-click now toggles zoom, that handler swallowed the bar's click too. The preview handler now steps aside when the point is inside the bar's bounds (SocialBarElement.RenderSize, translated to canvas). Audited and left alone because they are correct: left-down → resize handle / element drag / deselect; move → zoom drag before edit drag (by design); left-up → EndPreviewDrag; right-up → zoom-drag release then the Ctrl swallow. Build Debug 0 warnings, 22 tests pass across ZoomBox, PreviewHistory and SocialBar.
This commit is contained in:
@@ -402,6 +402,18 @@ public partial class PreviewPane : UserControl
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
/// <summary>Is this canvas point inside the social bar? It is a full-width strip at the top or
|
||||
/// bottom of the frame and it consumes its own click, so the preview's tunnelling handler has
|
||||
/// to step aside (see <c>Preview_MouseLeftButtonDown</c>).</summary>
|
||||
private bool IsOverSocialBar(Point canvasPoint)
|
||||
{
|
||||
if (DataContext is not MainViewModel { SocialBarVisible: true }) return false;
|
||||
if (SocialBarElement.ActualHeight <= 0) return false;
|
||||
|
||||
var topLeft = SocialBarElement.TranslatePoint(new Point(0, 0), CanvasGrid);
|
||||
return new Rect(topLeft, SocialBarElement.RenderSize).Contains(canvasPoint);
|
||||
}
|
||||
|
||||
private void SocialsButton_MouseEnter(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (SocialBarElement == null) return;
|
||||
@@ -453,6 +465,16 @@ public partial class PreviewPane : UserControl
|
||||
var vm = DataContext as MainViewModel;
|
||||
if (vm is null) return;
|
||||
|
||||
var grid = (Grid)sender;
|
||||
var toCanvas = CanvasGrid.TransformToVisual(grid).Inverse;
|
||||
var p = toCanvas.Transform(e.GetPosition(grid));
|
||||
|
||||
// The social bar owns its own left-click (toggle top ⇄ bottom). This handler is the
|
||||
// TUNNELLING preview event, so it fires before the bar's bubbling handler: without this
|
||||
// guard the bar would be unclickable in preview mode (zoom would win) and, in edit mode,
|
||||
// it would drag whatever layer sat underneath it.
|
||||
if (IsOverSocialBar(p)) return;
|
||||
|
||||
// Preview mode (EDIT off): the left button drives the zoom box — the common gesture in
|
||||
// the mode where nothing is editable. Dragging it afterwards is handled by MouseMove.
|
||||
if (!vm.IsEditMode)
|
||||
@@ -461,10 +483,6 @@ public partial class PreviewPane : UserControl
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var grid = (Grid)sender;
|
||||
var toCanvas = CanvasGrid.TransformToVisual(grid).Inverse;
|
||||
var p = toCanvas.Transform(e.GetPosition(grid));
|
||||
var selected = vm.SelectedElement;
|
||||
|
||||
if (selected is { } sel && IsDraggableElement(sel) && HitHandle(e.GetPosition(grid), sel))
|
||||
@@ -603,7 +621,9 @@ public partial class PreviewPane : UserControl
|
||||
|
||||
vm.ToggleZoom();
|
||||
e.Handled = true;
|
||||
} private void Preview_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
|
||||
}
|
||||
|
||||
private void Preview_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (_isZoomDragging)
|
||||
{
|
||||
@@ -614,6 +634,13 @@ public partial class PreviewPane : UserControl
|
||||
e.Handled = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// WPF's PopupControlService opens a context menu on right-button-UP, not down — so
|
||||
// handling the Down event alone still let a menu appear under a Ctrl+right-click (found
|
||||
// by the creator in edit mode, 2026-11-01). Swallow the Up event too, in both modes:
|
||||
// Down decides the action, Up must not undo that decision.
|
||||
if ((Keyboard.Modifiers & ModifierKeys.Control) != 0)
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void EndPreviewDrag(Grid grid)
|
||||
|
||||
@@ -104,7 +104,7 @@ The app is a **director's control surface**, not an editor. This replaces the OB
|
||||
|
||||
- **Left panel:** `EditingActive` is an explicit `EDIT` toggle, not a mode inferred from `StreamStatus`. On = scene layers + properties; off = YouTube chat. Go Live turns editing off and stopping restores it; recording does not automatically switch it off. The staged scene is the preview/edit target; `LiveScene` is the program output.
|
||||
- **Top bar:** the `EDIT` toggle sits beside the REC/ON-AIR session controls; the brand and account surfaces remain at the sides. Its **right edge aligns with the layers panel below** (`TopBar` column 0 is a fixed **352** = work-area margin 8 + 360px column − the bar's own 16px padding), so the button and the panel share an edge. The **settings gear moved to the preview rail** (2026-11-01): first tab, orange (`Brush.Attention`), gear icon only — left-click opens the app menu (Settings / Bug / Feature / About), right-click goes straight to App Settings.
|
||||
- **Preview gestures (2026-11-01):** *edit mode* — left selects/drags/resizes, right opens the context menu, **Ctrl+right toggles the zoom box**. *Preview mode* — **left toggles the zoom box**, right opens the context menu; **Ctrl+right is swallowed** (no chord while live or recording — one hand, always). Menus exist on the webcam layer and the backdrop; every other layer right-clicks through to the backdrop menu. Left-dragging with the zoom box open moves it, in both modes.
|
||||
- **Preview gestures (2026-11-01):** *edit mode* — left selects/drags/resizes, right opens the context menu, **Ctrl+right toggles the zoom box**. *Preview mode* — **left toggles the zoom box**, right opens the context menu; **Ctrl+right does nothing at all** (no chord while live or recording — one hand, always). ⚠️ **Both the Down and the Up event must be handled for a Ctrl+right-click**: WPF's `PopupControlService` opens a context menu on right-button-**up**, so suppressing only the down event leaves the menu appearing under the gesture (found 2026-11-01 in edit mode). Menus exist on the webcam layer and the backdrop; every other layer right-clicks through to the backdrop menu. Left-dragging with the zoom box open moves it, in both modes. The social bar consumes its own click (toggle top ⇄ bottom), and the preview's tunnelling handler steps aside for it — otherwise the bar is unclickable in preview mode and drags the layer beneath it in edit mode.
|
||||
- **Preview undo/redo (2026-11-01):** `Ctrl+Z` / `Ctrl+Shift+Z`, window-level bindings, live only while `EditingActive` — undo with the preview showing program output would rewrite a scene nobody is looking at. `Models/PreviewHistory` snapshots element **references** plus geometry, visibility, order and membership, so move / resize / reorder / add / remove / hide all undo in one step per gesture (`PushPreviewUndo` is called once at drag or resize start, never inside the move loop). Property edits (colour, opacity, border, font) are **not** captured yet — stated in the type's doc comment so nobody assumes otherwise. The stack clears on layout load. Guard: `ytLive.Tests/PreviewHistoryTests.cs`.
|
||||
- **Developer affordances are compiled out of release, not hidden.** Any control that must never ship (today: the all-resolutions override) lives in its own `UserControl` whose `Page` and `Compile` items are removed by `ytLive.csproj` when `$(Configuration) != 'Debug'`, and is added to its host at runtime inside `#if DEBUG` (`OverlayHost`). A collapsed row still exists in the visual tree of every shipped copy; "not compiled" is the only claim worth making. Label such rows with `Brush.Attention` (orange) while they are visible in Debug. Guard: `ytLive.Tests/OutputProfileTests.cs` asserts the build rule, and `Helpers/DevBuild.cs` is the single source for "is this a dev build".
|
||||
- **Scene strip:** five fixed-size cards above the preview show the scene name and hotkey; the staged scene carries a `PROGRAM` badge, and staged/live borders use orange. Click stages a scene while idle; while streaming or recording it changes program output and starts the selected transition.
|
||||
|
||||
Reference in New Issue
Block a user