feat(ui): gear to the rail, EDIT on the panel edge, preview undo/redo
Three creator directives (2026-11-01), done ahead of the surge. **Gear moved to the preview rail** — first tab, orange (Brush.Attention), gear icon only. Left-click opens the same app menu the top bar gear owned (Settings / Bug / Feature / About), right-click goes straight to App Settings; both behaviours moved with it, so nothing lost an entry point. TopBar keeps the wordmark and EDIT. **EDIT right edge aligned to the layers panel.** The work area is margin 8 + a 360px column, the top bar is padding 16, so the shared edge is 352 inside the bar. TopBar column 0 is now a fixed 352 grid with EDIT right-aligned in it — alignment by arithmetic instead of by eye. **Preview undo/redo: Ctrl+Z / Ctrl+Shift+Z.** Models/PreviewHistory snapshots element REFERENCES plus geometry, visibility, order and membership — a deep clone would mirror every property of a dozen element subclasses and quietly miss the next one added. One snapshot per gesture (pushed at drag/resize start, never in the move loop), bounded at 50, redo survives multiple undos, cleared on layout load. Gated on EditingActive: undo while the preview shows program output would rewrite a scene nobody is looking at. Honest scope, in the type's doc comment: layout edits only. Colour/opacity/border/font edits are not captured yet, so Ctrl+Z after one of those restores the last layout change. 6 tests in PreviewHistoryTests; 19 pass across it and the neighbouring UI classes; Debug and Release both build at 0 warnings.
This commit is contained in:
@@ -208,9 +208,9 @@ public partial class MainViewModel : ViewModelBase
|
||||
AddSourceCommand = new RelayCommand(parameter => AddSource(parameter));
|
||||
AddWebcamCommand = new RelayCommand(_ => _ = AddWebcamToStagedSceneAsync());
|
||||
AddImageCommand = new RelayCommand(_ => AddImage());
|
||||
RemoveSourceCommand = new RelayCommand(element => RemoveElement(element as SceneElement));
|
||||
RemoveSourceCommand = new RelayCommand(element => { PushPreviewUndo(); RemoveElement(element as SceneElement); });
|
||||
EditElementCommand = new RelayCommand(element => BeginEditElement(element as SceneElement));
|
||||
ToggleElementVisibilityCommand = new RelayCommand(element => ToggleElementVisibility(element as SceneElement));
|
||||
ToggleElementVisibilityCommand = new RelayCommand(element => { PushPreviewUndo(); ToggleElementVisibility(element as SceneElement); });
|
||||
BrowseAlertVideoCommand = new RelayCommand(element => BrowseAlertVideo(element as Source), element => element is Source { Type: SourceType.AlertBox });
|
||||
ResetAlertVideoCommand = new RelayCommand(element => ResetAlertVideo(element as Source), element => element is Source { Type: SourceType.AlertBox });
|
||||
ChangeWebcamCommand = new RelayCommand(_ => _ = ChangeWebcamAsync(), _ => CanChangeWebcam);
|
||||
@@ -233,6 +233,7 @@ public partial class MainViewModel : ViewModelBase
|
||||
ToggleGameMuteCommand = new RelayCommand(_ => ToggleGameMute());
|
||||
OpenMicPickerCommand = new RelayCommand(_ => PickMicrophone());
|
||||
OpenSettingsCommand = new RelayCommand(_ => ShowOverlay(nameof(IsSettingsOpen), "App Settings"));
|
||||
InitPreviewHistory();
|
||||
OpenBugCommand = new RelayCommand(_ => ShowOverlay(nameof(IsBugOpen), "Report Bug"));
|
||||
OpenFeatureCommand = new RelayCommand(_ => ShowOverlay(nameof(IsFeatureOpen), "Feature Request"));
|
||||
OpenAboutCommand = new RelayCommand(_ => ShowOverlay(nameof(IsAboutOpen), "About"));
|
||||
@@ -450,6 +451,7 @@ public partial class MainViewModel : ViewModelBase
|
||||
{
|
||||
_isLoading = false;
|
||||
}
|
||||
ClearPreviewHistory();
|
||||
StagedScene = Scenes.FirstOrDefault(s => SceneCatalog.Is(s.Name, SceneCatalog.Starting)) ?? Scenes.FirstOrDefault();
|
||||
UpdateActiveBackground();
|
||||
UpdateActiveChatBoxPreviews();
|
||||
|
||||
Reference in New Issue
Block a user