Revert "Fix UI polish: scrollbar deselect, web source inline buttons, countdown in Sources, volume click-to-position, meter decay"
This reverts commit dc91c855ef.
This commit is contained in:
+37
-29
@@ -278,10 +278,6 @@
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid Margin="0,2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
@@ -301,7 +297,7 @@
|
||||
</ContextMenu>
|
||||
</Grid.ContextMenu>
|
||||
|
||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Name}" VerticalAlignment="Center"
|
||||
<TextBlock Grid.Column="0" Text="{Binding Name}" VerticalAlignment="Center"
|
||||
Padding="4,2" TextTrimming="CharacterEllipsis">
|
||||
<TextBlock.Style>
|
||||
<Style TargetType="TextBlock">
|
||||
@@ -315,7 +311,7 @@
|
||||
</TextBlock.Style>
|
||||
</TextBlock>
|
||||
|
||||
<TextBox Grid.Row="0" Grid.Column="0" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"
|
||||
<TextBox Grid.Column="0" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"
|
||||
Background="#0f3460" Foreground="#e0e0e0" BorderThickness="0"
|
||||
Padding="4,2" VerticalContentAlignment="Center"
|
||||
IsVisibleChanged="SourceNameBox_IsVisibleChanged"
|
||||
@@ -332,38 +328,27 @@
|
||||
</TextBox.Style>
|
||||
</TextBox>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="1" ToolTip="Edit Source Name"
|
||||
<Button Grid.Column="1" ToolTip="Edit Source Name"
|
||||
Command="{Binding DataContext.EditElementCommand, RelativeSource={RelativeSource AncestorType=ListBox}}"
|
||||
CommandParameter="{Binding}" Style="{StaticResource IconButton}">
|
||||
<Path Data="M3,17.25V21h3.75L17.81,9.94l-3.75,-3.75L3,17.25zM20.71,7.04c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.39,-0.39 -1.02,-0.39 -1.41,0l-1.83,1.83 3.75,3.75 1.83,-1.83z"
|
||||
Fill="#d0d0d0" Width="13" Height="13" Stretch="Uniform"/>
|
||||
</Button>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="2" Style="{StaticResource EyeButton}"
|
||||
<Button Grid.Column="2" Style="{StaticResource EyeButton}"
|
||||
Command="{Binding DataContext.ToggleElementVisibilityCommand, RelativeSource={RelativeSource AncestorType=ListBox}}"
|
||||
CommandParameter="{Binding}">
|
||||
<Path Style="{StaticResource EyeIconStyle}" Fill="#d0d0d0"
|
||||
Width="13" Height="13" Stretch="Uniform"/>
|
||||
</Button>
|
||||
|
||||
<Button Grid.Row="0" Grid.Column="3" ToolTip="Remove Source"
|
||||
<Button Grid.Column="3" ToolTip="Remove Source"
|
||||
Command="{Binding DataContext.RemoveSourceCommand, RelativeSource={RelativeSource AncestorType=ListBox}}"
|
||||
CommandParameter="{Binding}" Style="{StaticResource IconButton}"
|
||||
Visibility="{Binding IsBackdrop, Converter={StaticResource HiddenBoolToVis}}">
|
||||
<Path Data="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z"
|
||||
Fill="#d0d0d0" Width="13" Height="13" Stretch="Uniform"/>
|
||||
</Button>
|
||||
|
||||
<!-- Countdown timer: inline in source list row 1 -->
|
||||
<DockPanel Grid.Row="1" Grid.ColumnSpan="4" Margin="8,2,4,2"
|
||||
Visibility="{Binding Type, Converter={StaticResource SourceTypeToCountdownVis}, ConverterParameter=Countdown}">
|
||||
<TextBlock Text="{Binding TimerMinutes, StringFormat={}{0} min}" Foreground="#a0a0b0" FontSize="11"
|
||||
DockPanel.Dock="Right" VerticalAlignment="Center" Margin="6,0,0,0" Width="42"/>
|
||||
<Slider DockPanel.Dock="Left" Width="130" Minimum="1" Maximum="30"
|
||||
Value="{Binding TimerMinutes, Mode=TwoWay}"
|
||||
VerticalAlignment="Center" TickFrequency="1" IsSnapToTickEnabled="True"
|
||||
Style="{StaticResource CompactSlider}"/>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
@@ -381,7 +366,7 @@
|
||||
Visibility="{Binding SelectedElement, Converter={StaticResource NotNullToVis}}">
|
||||
<TextBlock Text="ELEMENTS" Style="{StaticResource SectionHeader}" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<ScrollViewer x:Name="ElementsScrollViewer" Grid.Row="7" VerticalScrollBarVisibility="Auto" Background="Transparent"
|
||||
<ScrollViewer Grid.Row="7" VerticalScrollBarVisibility="Auto" Background="Transparent"
|
||||
Visibility="{Binding SelectedElement, Converter={StaticResource NotNullToVis}}">
|
||||
<StackPanel x:Name="ElementsPanel" Margin="0,4,0,0">
|
||||
<!-- Opacity + mirror/shape (draggable elements: image, webcam) -->
|
||||
@@ -440,25 +425,48 @@
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Web source config -->
|
||||
<StackPanel Visibility="{Binding SelectedElement.Type, Converter={StaticResource SourceTypeToWebVis}, ConverterParameter=WebSource}" Margin="0,0,0,8">
|
||||
<TextBlock Text="URI" Foreground="#a0a0b0" FontSize="11" Margin="0,0,0,2"/>
|
||||
<DockPanel>
|
||||
<!-- Countdown config -->
|
||||
<StackPanel Visibility="{Binding SelectedElement.Type, Converter={StaticResource SourceTypeToCountdownVis}, ConverterParameter=Countdown}" Margin="0,0,0,8">
|
||||
<TextBlock Text="Timer (minutes)" Foreground="#a0a0b0" FontSize="11" Margin="0,0,0,2"/>
|
||||
<DockPanel Margin="0,0,0,6">
|
||||
<Button DockPanel.Dock="Right" Style="{StaticResource IconButton}"
|
||||
Width="22" Height="22" ToolTip="Revert"
|
||||
Click="CountdownRevert_Click" Margin="4,0,0,0">
|
||||
<Path Data="M5,5 L15,15 M15,5 L5,15" Stroke="#e94560" StrokeThickness="2"
|
||||
Width="14" Height="14" Stretch="Uniform"/>
|
||||
</Button>
|
||||
<Button DockPanel.Dock="Right" Style="{StaticResource IconButton}"
|
||||
IsEnabled="False" Width="22" Height="22" Margin="4,0,0,0">
|
||||
<Path Data="M4,9 L8,14 L16,4" Stroke="#22c55e" StrokeThickness="2"
|
||||
Width="14" Height="14" Stretch="Uniform"/>
|
||||
</Button>
|
||||
<Slider DockPanel.Dock="Left" Width="120" Minimum="1" Maximum="60"
|
||||
Value="{Binding SelectedElement.TimerMinutes, Mode=TwoWay}"
|
||||
VerticalAlignment="Center" TickFrequency="1" IsSnapToTickEnabled="True"/>
|
||||
<TextBlock Text="{Binding SelectedElement.TimerMinutes}" Foreground="#a0a0b0" FontSize="11"
|
||||
VerticalAlignment="Center" Margin="8,0,0,0" Width="20"/>
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Web source config -->
|
||||
<StackPanel Visibility="{Binding SelectedElement.Type, Converter={StaticResource SourceTypeToWebVis}, ConverterParameter=WebSource}" Margin="0,0,0,8">
|
||||
<TextBlock Text="URI" Foreground="#a0a0b0" FontSize="11" Margin="0,0,0,2"/>
|
||||
<TextBox Text="{Binding SelectedElement.WebUri, UpdateSourceTrigger=PropertyChanged}"
|
||||
Background="#0f3460" Foreground="#e0d0e0" BorderThickness="1"
|
||||
BorderBrush="#2c3a5c" Padding="4,2" FontSize="12"
|
||||
ToolTip="https://example.com"/>
|
||||
<DockPanel Margin="0,4,0,0">
|
||||
<Button DockPanel.Dock="Right" Style="{StaticResource IconButton}"
|
||||
Width="22" Height="22" ToolTip="Revert"
|
||||
Click="WebRevert_Click" Margin="4,0,0,0">
|
||||
<Path Data="M5,5 L15,15 M15,5 L5,15" Stroke="#e94560" StrokeThickness="2"
|
||||
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"
|
||||
ToolTip="https://example.com"/>
|
||||
<Button DockPanel.Dock="Right" Style="{StaticResource IconButton}"
|
||||
IsEnabled="False" Width="22" Height="22" Margin="4,0,0,0">
|
||||
<Path Data="M4,9 L8,14 L16,4" Stroke="#22c55e" StrokeThickness="2"
|
||||
Width="14" Height="14" Stretch="Uniform"/>
|
||||
</Button>
|
||||
</DockPanel>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
+3
-18
@@ -83,11 +83,8 @@ public partial class MainWindow : Window
|
||||
|
||||
private void VolumeSlider_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is Slider slider && ClickIsOnTrackBackground(slider, e))
|
||||
{
|
||||
if (sender is Slider slider)
|
||||
SetSliderValueFromClick(slider, e);
|
||||
e.Handled = true;
|
||||
}
|
||||
if (sender is FrameworkElement { DataContext: MainViewModel vm })
|
||||
vm.SetVolumeAdjusting(true);
|
||||
}
|
||||
@@ -106,11 +103,8 @@ public partial class MainWindow : Window
|
||||
|
||||
private void GameVolumeSlider_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (sender is Slider slider && ClickIsOnTrackBackground(slider, e))
|
||||
{
|
||||
if (sender is Slider slider)
|
||||
SetSliderValueFromClick(slider, e);
|
||||
e.Handled = true;
|
||||
}
|
||||
if (sender is FrameworkElement { DataContext: MainViewModel vm })
|
||||
vm.SetGameVolumeAdjusting(true);
|
||||
}
|
||||
@@ -127,15 +121,6 @@ public partial class MainWindow : Window
|
||||
vm.SetGameVolumeAdjusting(false);
|
||||
}
|
||||
|
||||
private static bool ClickIsOnTrackBackground(Slider slider, MouseButtonEventArgs e)
|
||||
{
|
||||
var track = slider.Template.FindName("PART_Track", slider) as System.Windows.Controls.Primitives.Track;
|
||||
if (track == null) return false;
|
||||
if (track.Thumb != null && IsDescendantOf(e.OriginalSource as DependencyObject, track.Thumb))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void SetSliderValueFromClick(Slider slider, MouseButtonEventArgs e)
|
||||
{
|
||||
var track = slider.Template.FindName("PART_Track", slider) as System.Windows.Controls.Primitives.Track;
|
||||
@@ -224,7 +209,7 @@ public partial class MainWindow : Window
|
||||
if (e.OriginalSource is not DependencyObject original) return;
|
||||
if (IsDescendantOf(original, PreviewGrid)) return;
|
||||
if (IsDescendantOf(original, SourceList)) return;
|
||||
if (IsDescendantOf(original, ElementsScrollViewer)) return;
|
||||
if (IsDescendantOf(original, ElementsPanel)) return;
|
||||
_viewModel.SelectedElement = null;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -96,7 +96,7 @@ public class Source : SceneElement
|
||||
public int TimerMinutes
|
||||
{
|
||||
get => _timerMinutes;
|
||||
set => Set(ref _timerMinutes, Math.Clamp(value, 1, 30));
|
||||
set => Set(ref _timerMinutes, Math.Clamp(value, 1, 60));
|
||||
}
|
||||
|
||||
// Web source config
|
||||
|
||||
@@ -1,27 +1,18 @@
|
||||
namespace ytLive.Services.Audio;
|
||||
|
||||
/// <summary>
|
||||
/// Computes the smoothed level (0..1) from captured samples. Pure —
|
||||
/// Computes the smoothed mic level (0..1) from captured samples. Pure —
|
||||
/// unit-tested; the <see cref="AudioMixer"/> only feeds it and forwards the
|
||||
/// result. RMS-based so it tracks perceived loudness, smoothed so the meter
|
||||
/// does not flicker. Supports asymmetric smoothing: fast attack (rise) and
|
||||
/// configurable decay (fall) so the meter responds quickly to silence.
|
||||
/// does not flicker.
|
||||
/// </summary>
|
||||
public sealed class AudioLevelMeter
|
||||
{
|
||||
private const float Smoothing = 0.2f;
|
||||
private float _level;
|
||||
|
||||
public float Level => _level;
|
||||
|
||||
public AudioLevelMeter(float attackSmoothing = 0.2f, float decaySmoothing = 0.08f)
|
||||
{
|
||||
AttackSmoothing = attackSmoothing;
|
||||
DecaySmoothing = decaySmoothing;
|
||||
}
|
||||
|
||||
public float AttackSmoothing { get; }
|
||||
public float DecaySmoothing { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Maps a linear level (0..1) onto the meter's display scale: -60 dBFS..0 dBFS
|
||||
/// spread linearly across 0..1, with +10 dB of input amplification. Linear RMS
|
||||
@@ -53,8 +44,7 @@ public sealed class AudioLevelMeter
|
||||
}
|
||||
|
||||
var rms = (float)Math.Sqrt(sumSquares / count);
|
||||
var smoothing = rms > _level ? AttackSmoothing : DecaySmoothing;
|
||||
_level = _level * (1 - smoothing) + rms * smoothing;
|
||||
_level = _level * (1 - Smoothing) + rms * Smoothing;
|
||||
return _level;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ public sealed class AudioMixer : IDisposable
|
||||
_mic = mic;
|
||||
_loopback = loopback;
|
||||
_meter = new AudioLevelMeter();
|
||||
_loopbackMeter = new AudioLevelMeter(attackSmoothing: 0.2f, decaySmoothing: 0.08f);
|
||||
_loopbackMeter = new AudioLevelMeter();
|
||||
_log = log;
|
||||
_micGain = micGain;
|
||||
_loopbackGain = loopbackGain;
|
||||
|
||||
@@ -818,12 +818,12 @@ No changes to `MusicPlayer`, the 0.20 cap, the ducker, or the meter zones. Build
|
||||
1. ✅ TRAX volume — `LocalGain = GameAudioVolume * 0.2` so TRAX is 20% of the desktop audio slider (was 100%, now quieter)
|
||||
2. ✅ TRAX tooltip — replaced `ToolTip` binding with `ToolTipService.ToolTip` + `Placement="Top"` to fix z-order inside Viewbox overlay
|
||||
3. ✅ Mic meter boost — `MeterLevel` multiplied by 1.2× before clamping so the bar reads ~20% higher at same input level
|
||||
4. ✅ Click-to-position sliders — clicking anywhere on the mic/game volume slider track now jumps the thumb to that position before starting the drag (fixed: RepeatButton no longer overrides click position; Thumb drag still works)
|
||||
4. ✅ Click-to-position sliders — clicking anywhere on the mic/game volume slider track now jumps the thumb to that position before starting the drag
|
||||
5. ✅ Backdrop visibility — the dedicated `<Image>` now binds `Visibility` to `BackdropVisible` (ViewModel property); compositor checks `IsVisible` before blit
|
||||
6. ✅ Rename "Backdrop" → "Game Capture" in `EnsureBackdrop()` + test assertions
|
||||
7. ✅ Elements panel — new "ELEMENTS" section beneath Sources list; per-element config with live preview, ✕ revert, ✓ applied indicator
|
||||
8. ✅ Webcam border config — color hex input + color swatch picker, border thickness 0–10 slider
|
||||
9. ✅ Countdown source — `SourceType.Countdown`, pick list (Starting/BRB scenes only), timer minutes 1–30 default 15, inline slider in source list row
|
||||
9. ✅ Countdown source — `SourceType.Countdown`, pick list (Starting/BRB scenes only), timer minutes 1–60 default 15
|
||||
10. ✅ Web source — `SourceType.WebSource`, pick list (all scenes), URI text input
|
||||
|
||||
---
|
||||
|
||||
Reference in New Issue
Block a user