TASK 58: the properties panel wears the theme (no more light-system chrome)

The creator asked why the Stream Alerts "Display" drop-down was not in the same
style as the other drop-downs. It was never given the theme's YtComboBox style -
only a hand-painted Background/Foreground. Setting colours changes the paint, not
the template, so WPF still drew the light system ComboBox (grey border, system
arrow, white popup list) on top of the dark panel. The chat Font drop-down was a
copy of the same mistake, and every check box was the light system one.

The sweep of the whole properties panel (then the app):
  - ComboBox x2 (chat Font, alert Display) -> YtComboBox, hand-painted colours gone
  - TextBox x16 in the properties panel -> YtTextBoxCompact (new, BasedOn YtTextBox:
    11px / padding 4,2 - the panel is dense, the full 13px box would double it)
  - CheckBox x2 (chat) + x3 (preview broadcast) + x1 (socials dialog) -> YtCheckBox
    (new: a 14x14 rounded box + tick path, accent fill when checked)
  - the layer-rename field -> YtTextBoxCompact via BasedOn, still borderless
  - buttons, pills, sliders: already themed, untouched

The sweep also killed a typo'd foreground (#e0d0e0 for #e0e0e0) and the only
remaining hand-painted colour is the deliberate dimming of the two read-only path
fields.

Guard: ytLive.Tests/PropertiesStyleTests.cs (the ONE Good Dog test) parses the app
XAML and fails if an unstyled drop-down, check box or properties field comes back.
431/431 green, 0 warnings.
This commit is contained in:
2026-10-21 19:46:25 -07:00
parent 17aa0273a9
commit 2273d20160
12 changed files with 262 additions and 51 deletions
+24 -39
View File
@@ -155,12 +155,11 @@
</TextBlock>
<TextBox Grid.Column="0" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"
Background="#0f3460" Foreground="#e0e0e0" BorderThickness="0"
Padding="4,2" VerticalContentAlignment="Center"
BorderThickness="0" FontSize="12"
IsVisibleChanged="SourceNameBox_IsVisibleChanged"
KeyDown="SourceNameBox_KeyDown" LostFocus="SourceNameBox_LostFocus">
<TextBox.Style>
<Style TargetType="TextBox">
<Style TargetType="TextBox" BasedOn="{StaticResource YtTextBoxCompact}">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsEditing}" Value="True">
@@ -264,22 +263,18 @@
<DockPanel Margin="0,0,0,4">
<TextBlock DockPanel.Dock="Left" Text="X" Foreground="#a0a0b0" FontSize="11" VerticalAlignment="Center" Width="16"/>
<TextBox Text="{Binding SelectedElement.X, UpdateSourceTrigger=PropertyChanged, StringFormat=F0}"
Background="#0f3460" Foreground="#e0d0e0" BorderThickness="1"
BorderBrush="#2c3a5c" Padding="4,2" FontSize="12"/>
Style="{StaticResource YtTextBoxCompact}"/>
<TextBlock DockPanel.Dock="Left" Text=" Y" Foreground="#a0a0b0" FontSize="11" VerticalAlignment="Center" Width="20" Margin="8,0,0,0"/>
<TextBox Text="{Binding SelectedElement.Y, UpdateSourceTrigger=PropertyChanged, StringFormat=F0}"
Background="#0f3460" Foreground="#e0d0e0" BorderThickness="1"
BorderBrush="#2c3a5c" Padding="4,2" FontSize="12"/>
Style="{StaticResource YtTextBoxCompact}"/>
</DockPanel>
<DockPanel Margin="0,0,0,4">
<TextBlock DockPanel.Dock="Left" Text="W" Foreground="#a0a0b0" FontSize="11" VerticalAlignment="Center" Width="16"/>
<TextBox Text="{Binding SelectedElement.Width, UpdateSourceTrigger=PropertyChanged, StringFormat=F0}"
Background="#0f3460" Foreground="#e0d0e0" BorderThickness="1"
BorderBrush="#2c3a5c" Padding="4,2" FontSize="12"/>
Style="{StaticResource YtTextBoxCompact}"/>
<TextBlock DockPanel.Dock="Left" Text=" H" Foreground="#a0a0b0" FontSize="11" VerticalAlignment="Center" Width="20" Margin="8,0,0,0"/>
<TextBox Text="{Binding SelectedElement.Height, UpdateSourceTrigger=PropertyChanged, StringFormat=F0}"
Background="#0f3460" Foreground="#e0d0e0" BorderThickness="1"
BorderBrush="#2c3a5c" Padding="4,2" FontSize="12"/>
Style="{StaticResource YtTextBoxCompact}"/>
</DockPanel>
</StackPanel>
@@ -291,8 +286,7 @@
Click="WebcamBorderColorPicker_Click" Margin="4,0,0,0"
ToolTip="Pick color"/>
<TextBox Text="{Binding SelectedElement.BorderColor, UpdateSourceTrigger=PropertyChanged}"
Background="#0f3460" Foreground="#e0d0e0" BorderThickness="1"
BorderBrush="#2c3a5c" Padding="4,2" FontSize="12"
Style="{StaticResource YtTextBoxCompact}"
MaxLength="7" ToolTip="#RRGGBB"/>
</DockPanel>
<TextBlock Text="Border Thickness" Foreground="#a0a0b0" FontSize="11" Margin="0,0,0,2"/>
@@ -378,22 +372,18 @@
<DockPanel Margin="0,0,0,4">
<TextBlock DockPanel.Dock="Left" Text="X" Foreground="#a0a0b0" FontSize="11" VerticalAlignment="Center" Width="16"/>
<TextBox Text="{Binding SelectedElement.X, UpdateSourceTrigger=PropertyChanged, StringFormat=F0}"
Background="#0f3460" Foreground="#e0d0e0" BorderThickness="1"
BorderBrush="#2c3a5c" Padding="4,2" FontSize="12"/>
Style="{StaticResource YtTextBoxCompact}"/>
<TextBlock DockPanel.Dock="Left" Text=" Y" Foreground="#a0a0b0" FontSize="11" VerticalAlignment="Center" Width="20" Margin="8,0,0,0"/>
<TextBox Text="{Binding SelectedElement.Y, UpdateSourceTrigger=PropertyChanged, StringFormat=F0}"
Background="#0f3460" Foreground="#e0d0e0" BorderThickness="1"
BorderBrush="#2c3a5c" Padding="4,2" FontSize="12"/>
Style="{StaticResource YtTextBoxCompact}"/>
</DockPanel>
<DockPanel Margin="0,0,0,4">
<TextBlock DockPanel.Dock="Left" Text="W" Foreground="#a0a0b0" FontSize="11" VerticalAlignment="Center" Width="16"/>
<TextBox Text="{Binding SelectedElement.Width, UpdateSourceTrigger=PropertyChanged, StringFormat=F0}"
Background="#0f3460" Foreground="#e0d0e0" BorderThickness="1"
BorderBrush="#2c3a5c" Padding="4,2" FontSize="12"/>
Style="{StaticResource YtTextBoxCompact}"/>
<TextBlock DockPanel.Dock="Left" Text=" H" Foreground="#a0a0b0" FontSize="11" VerticalAlignment="Center" Width="20" Margin="8,0,0,0"/>
<TextBox Text="{Binding SelectedElement.Height, UpdateSourceTrigger=PropertyChanged, StringFormat=F0}"
Background="#0f3460" Foreground="#e0d0e0" BorderThickness="1"
BorderBrush="#2c3a5c" Padding="4,2" FontSize="12"/>
Style="{StaticResource YtTextBoxCompact}"/>
</DockPanel>
<TextBlock Text="URI" Foreground="#a0a0b0" FontSize="11" Margin="0,0,0,2"/>
<DockPanel>
@@ -410,8 +400,7 @@
Width="14" Height="14" Stretch="Uniform"/>
</Button>
<TextBox Text="{Binding SelectedElement.WebUri, UpdateSourceTrigger=PropertyChanged}"
Background="#0f3460" Foreground="#e0d0e0" BorderThickness="1"
BorderBrush="#2c3a5c" Padding="4,2" FontSize="12"
Style="{StaticResource YtTextBoxCompact}"
ToolTip="https://example.com"/>
</DockPanel>
</StackPanel>
@@ -434,7 +423,7 @@
<TextBlock DockPanel.Dock="Left" Text="Font" Foreground="#a0a0b0" FontSize="11" VerticalAlignment="Center" Width="70"/>
<ComboBox SelectedValue="{Binding SelectedElement.ChatFontFamily, Mode=TwoWay}"
SelectedValuePath="Content"
Background="#0f3460" Foreground="#e0e0e0" FontSize="11"
Style="{StaticResource YtComboBox}"
Width="140" VerticalAlignment="Center">
<ComboBoxItem Content="Segoe UI"/>
<ComboBoxItem Content="Arial"/>
@@ -449,24 +438,21 @@
<DockPanel Margin="0,0,0,4">
<TextBlock DockPanel.Dock="Left" Text="Font Color" Foreground="#a0a0b0" FontSize="11" VerticalAlignment="Center" Width="70"/>
<TextBox Text="{Binding SelectedElement.ChatFontColor, UpdateSourceTrigger=PropertyChanged}"
Background="#0f3460" Foreground="#e0e0e0" BorderThickness="1"
BorderBrush="#2c3a5c" Padding="4,2" FontSize="11" Width="80"/>
Style="{StaticResource YtTextBoxCompact}" Width="80"/>
</DockPanel>
<!-- Member Color -->
<DockPanel Margin="0,0,0,4">
<TextBlock DockPanel.Dock="Left" Text="Member" Foreground="#a0a0b0" FontSize="11" VerticalAlignment="Center" Width="70"/>
<TextBox Text="{Binding SelectedElement.ChatMemberColor, UpdateSourceTrigger=PropertyChanged}"
Background="#0f3460" Foreground="#e0e0e0" BorderThickness="1"
BorderBrush="#2c3a5c" Padding="4,2" FontSize="11" Width="80"/>
Style="{StaticResource YtTextBoxCompact}" Width="80"/>
</DockPanel>
<!-- Super Chat Color -->
<DockPanel Margin="0,0,0,4">
<TextBlock DockPanel.Dock="Left" Text="Super Chat" Foreground="#a0a0b0" FontSize="11" VerticalAlignment="Center" Width="70"/>
<TextBox Text="{Binding SelectedElement.ChatSuperChatColor, UpdateSourceTrigger=PropertyChanged}"
Background="#0f3460" Foreground="#e0e0e0" BorderThickness="1"
BorderBrush="#2c3a5c" Padding="4,2" FontSize="11" Width="80"/>
Style="{StaticResource YtTextBoxCompact}" Width="80"/>
</DockPanel>
<!-- Max Messages -->
@@ -482,8 +468,7 @@
<DockPanel Margin="0,0,0,4">
<TextBlock DockPanel.Dock="Left" Text="Background" Foreground="#a0a0b0" FontSize="11" VerticalAlignment="Center" Width="70"/>
<TextBox Text="{Binding SelectedElement.ChatBackgroundColor, UpdateSourceTrigger=PropertyChanged}"
Background="#0f3460" Foreground="#e0e0e0" BorderThickness="1"
BorderBrush="#2c3a5c" Padding="4,2" FontSize="11" Width="80"/>
Style="{StaticResource YtTextBoxCompact}" Width="80"/>
</DockPanel>
<!-- Background Opacity -->
@@ -505,9 +490,9 @@
</DockPanel>
<!-- Toggles -->
<CheckBox Content="Show timestamps" Foreground="#a0a0b0" FontSize="11" Margin="0,4,0,2"
<CheckBox Content="Show timestamps" Style="{StaticResource YtCheckBox}" Margin="0,4,0,2"
IsChecked="{Binding SelectedElement.ChatShowTimestamps, Mode=TwoWay}"/>
<CheckBox Content="Show badges" Foreground="#a0a0b0" FontSize="11" Margin="0,0,0,2"
<CheckBox Content="Show badges" Style="{StaticResource YtCheckBox}" Margin="0,0,0,2"
IsChecked="{Binding SelectedElement.ChatShowBadges, Mode=TwoWay}"/>
</StackPanel>
@@ -531,8 +516,8 @@
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding SelectedElement.AlertVideoPath, Mode=OneWay}"
IsReadOnly="True" Background="#0f3460" Foreground="#a0a0b0"
FontSize="11" VerticalAlignment="Center"/>
Style="{StaticResource YtTextBoxCompact}"
IsReadOnly="True" Foreground="#a0a0b0" VerticalAlignment="Center"/>
<Button Grid.Column="1" Content="Browse…" Command="{Binding BrowseAlertVideoCommand}"
CommandParameter="{Binding SelectedElement}" Style="{StaticResource YtButtonSecondary}"
Margin="4,0,0,0" Padding="8,2"/>
@@ -558,7 +543,7 @@
<TextBlock DockPanel.Dock="Left" Text="Display" Foreground="#a0a0b0" FontSize="11" VerticalAlignment="Center" Width="84"/>
<ComboBox SelectedValue="{Binding SelectedElement.AlertDisplayMethod, Mode=TwoWay}"
SelectedValuePath="Tag"
Background="#0f3460" Foreground="#e0e0e0" FontSize="11"
Style="{StaticResource YtComboBox}"
Width="140" VerticalAlignment="Center">
<ComboBoxItem Content="Scroll" Tag="TickerScroll"/>
<ComboBoxItem Content="Flash" Tag="Flash"/>
@@ -593,8 +578,8 @@
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding SelectedElement.CustomBackgroundPath, Mode=OneWay}"
IsReadOnly="True" Background="#0f3460" Foreground="#a0a0b0"
FontSize="11" VerticalAlignment="Center"/>
Style="{StaticResource YtTextBoxCompact}"
IsReadOnly="True" Foreground="#a0a0b0" VerticalAlignment="Center"/>
<Button Grid.Column="1" Content="Browse…" Command="{Binding BrowseBackgroundCommand}"
Style="{StaticResource YtButtonSecondary}" Margin="4,0,0,0" Padding="8,2"/>
</Grid>
+6 -6
View File
@@ -542,8 +542,8 @@
<ComboBox Style="{StaticResource YtComboBox}" Margin="0,0,0,10"
ItemsSource="{Binding BroadcastForm.VisibilityOptions}"
SelectedItem="{Binding BroadcastForm.Visibility}"/>
<CheckBox Content="Made for kids" Foreground="#e0e0e0" FontSize="12"
Margin="0,2,0,10"
<CheckBox Content="Made for kids" Style="{StaticResource YtCheckBox}"
FontSize="12" Margin="0,2,0,10"
IsChecked="{Binding BroadcastForm.MadeForKids}"/>
<TextBlock Text="SCHEDULED START" Style="{StaticResource YtLabel}" Margin="0,0,0,3"/>
<TextBlock Text="{Binding BroadcastForm.ScheduledStartText}"
@@ -655,8 +655,8 @@
<TextBlock Text="CHANNEL STANDING" Style="{StaticResource YtLabel}" Margin="0,0,0,2"/>
<TextBlock Text="{Binding Ypp.StandingDetailText}" Foreground="#888899" FontSize="11"
TextWrapping="Wrap" Margin="0,0,0,8"/>
<CheckBox Content="Two-Step Verification switched on" Foreground="#e0e0e0" FontSize="12"
Margin="0,2,0,0"
<CheckBox Content="Two-Step Verification switched on" Style="{StaticResource YtCheckBox}"
FontSize="12" Margin="0,2,0,0"
IsChecked="{Binding Ypp.TwoFactorEnabled}"/>
<Button Background="Transparent" BorderThickness="0" Cursor="Hand" HorizontalAlignment="Left"
Command="{Binding Ypp.OpenTwoStepCommand}" ToolTip="Open Google's 2-Step Verification page">
@@ -667,8 +667,8 @@
</Button.Template>
<TextBlock Text="Set up on Google →" Foreground="#5aa7ff" FontSize="12" Margin="0,0,0,6"/>
</Button>
<CheckBox Content="AdSense account linked" Foreground="#e0e0e0" FontSize="12"
Margin="0,2,0,0"
<CheckBox Content="AdSense account linked" Style="{StaticResource YtCheckBox}"
FontSize="12" Margin="0,2,0,0"
IsChecked="{Binding Ypp.AdSenseLinked}"/>
<Button Background="Transparent" BorderThickness="0" Cursor="Hand" HorizontalAlignment="Left"
Command="{Binding Ypp.OpenEarnCommand}" ToolTip="Open the YouTube Earn page">
+1 -1
View File
@@ -12,7 +12,7 @@ See [`schema.md`](../schema.md) for the memory-map conventions.
| `TopBar.xaml(.cs)` | Row 0 session surface (2026-09-22 redesign): brand + gear menu (left), one segmented REC|ON-AIR mode switch + world actions (Record: Start Recording · Stream: Go Live + Test) + reality line while running (dot/word/elapsed) + End (center), account zone — Sign In or avatar w/ Change Account/Logout context menu (right). `RefreshAvatar()`, `GearButton_Click` |
| `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). **TASK 57:** dragging a webcam under the vertical tier routes through `MainViewModel.MoveWebcamInVerticalTier` (the six-spot snap inside the cropped band) instead of free-floating over the master, and a resize re-snaps the tile onto its spot (TASK 57 Unit 2: the resize routes through `MainViewModel.ResizeWebcamInVerticalTier` — the Chat camera's two sizes, then the snap) |
| `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. **TASK 51:** the webcam properties carry the Background section — `RemoveBackgroundPill` / `BlurBackgroundPill` (`PillToggle`, radio-exclusive via `WebcamSceneConfig.RemoveBackground`/`BlurBackground`) + `BackgroundStrengthSlider` (0..1, 5% snaps, shown only while an effect is on). **TASK 57:** the webcam properties carry a Geometry section (X/Y/W/H) — manual placement of the camera, bound to the **live** placement (the one the current tier shows), gated on `IsWebcamSelected` (not `SelectedElement.IsWebcam` — the TASK 51 test finds that panel by binding text and would match twice); the Shape button's `Visibility` is bound to `CanToggleClipShape`, so the circle option is NOT OFFERED in the vertical Chat layout |
| `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. **TASK 51:** the webcam properties carry the Background section — `RemoveBackgroundPill` / `BlurBackgroundPill` (`PillToggle`, radio-exclusive via `WebcamSceneConfig.RemoveBackground`/`BlurBackground`) + `BackgroundStrengthSlider` (0..1, 5% snaps, shown only while an effect is on). **TASK 57:** the webcam properties carry a Geometry section (X/Y/W/H) — manual placement of the camera, bound to the **live** placement (the one the current tier shows), gated on `IsWebcamSelected` (not `SelectedElement.IsWebcam` — the TASK 51 test finds that panel by binding text and would match twice); the Shape button's `Visibility` is bound to `CanToggleClipShape`, so the circle option is NOT OFFERED in the vertical Chat layout. **TASK 58:** every drop-down, check box and field in the properties panel carries the theme's style (`YtComboBox`/`YtCheckBox`/`YtTextBoxCompact`) and paints no colour of its own — the guard is `ytLive.Tests/PropertiesStyleTests.cs` |
| `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 |