shared combo for all settings

This commit is contained in:
Orbmu2k
2026-05-22 08:52:44 +02:00
parent 295aaf3ee6
commit 34fde004d5
3 changed files with 201 additions and 65 deletions

View File

@@ -78,6 +78,9 @@
Background="{TemplateBinding Background}"
BorderThickness="0"
CaretBrush="{TemplateBinding Foreground}"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
Foreground="{TemplateBinding Foreground}"
HorizontalScrollBarVisibility="Hidden"
MaxLines="1"
@@ -92,6 +95,9 @@
<TextBlock
x:Name="ContentSite"
Margin="14,0,30,0"
FontFamily="{TemplateBinding FontFamily}"
FontSize="{TemplateBinding FontSize}"
FontWeight="{TemplateBinding FontWeight}"
VerticalAlignment="Center"
IsHitTestVisible="False"
Text="{TemplateBinding Text}"

View File

@@ -23,6 +23,52 @@
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<Window.Resources>
<DataTemplate x:Key="SharedValueEditorItemTemplate">
<StackPanel Orientation="Horizontal">
<Path
Width="12"
Height="12"
Margin="0,0,8,0"
Data="{Binding Source, Converter={StaticResource SettingMetaSourceToIconConverter}, Mode=OneWay}"
Fill="{DynamicResource TextSecondaryBrush}"
Stretch="Uniform" />
<TextBlock
Text="{Binding ValueName, Mode=OneWay}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />
</StackPanel>
</DataTemplate>
<controls:SearchableComboBox x:Key="SharedValueEditorResource"
Padding="8,4"
HorizontalAlignment="Stretch"
Foreground="{Binding State, Converter={StaticResource StateToColorConverter}, Mode=OneWay}"
behaviors:SettingValueValidationBehavior.Enabled="True"
Cursor=""
DeferSelectionUntilCommit="True"
IsEditable="True"
ItemsSource="{Binding ValueNameItems, Mode=OneWay}"
MaxDropDownHeight="400"
Placeholder="Search values..."
PreserveSelectionOnKeyboardFocus="True"
SyncSelectedItemToText="False"
Text="{Binding SelectedValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Validation.ErrorTemplate="{x:Null}"
ItemTemplate="{StaticResource SharedValueEditorItemTemplate}">
<controls:SearchableComboBox.Style>
<Style TargetType="controls:SearchableComboBox" BasedOn="{StaticResource {x:Type controls:SearchableComboBox}}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsModified}" Value="True">
<Setter Property="Foreground" Value="{DynamicResource TextPrimaryBrush}" />
<Setter Property="FontWeight" Value="Bold" />
</DataTrigger>
</Style.Triggers>
</Style>
</controls:SearchableComboBox.Style>
</controls:SearchableComboBox>
</Window.Resources>
<Window.InputBindings>
<KeyBinding
@@ -1180,14 +1226,14 @@
</Grid>
<!-- Settings ListView -->
<ListView
x:Name="SettingsListView"
Grid.Row="1"
behaviors:GridViewColumnResizeBehavior.EnableStarSizing="True"
behaviors:ScrollIntoViewForListView.Enable="{Binding ScrollIntoViewEnabled}"
ItemsSource="{Binding GroupedSettingsView}"
SelectedItem="{Binding SelectedSetting}"
Style="{StaticResource DarkListViewStyle}">
<Grid Grid.Row="1">
<ListView
x:Name="SettingsListView"
behaviors:GridViewColumnResizeBehavior.EnableStarSizing="True"
behaviors:ScrollIntoViewForListView.Enable="{Binding ScrollIntoViewEnabled}"
ItemsSource="{Binding GroupedSettingsView}"
SelectedItem="{Binding SelectedSetting}"
Style="{StaticResource DarkListViewStyle}">
<ListView.ItemContainerStyle>
<Style BasedOn="{StaticResource DarkListViewItemStyle}" TargetType="ListViewItem">
<Setter Property="BorderThickness" Value="2,0,0,0" />
@@ -1304,67 +1350,29 @@
Header="VALUE">
<GridViewColumn.CellTemplate>
<DataTemplate>
<DataTemplate.Resources>
<DataTemplate x:Key="SettingValueDisplayTemplate">
<TextBlock
x:Name="DisplayText"
Margin="12,0"
VerticalAlignment="Center"
Foreground="{Binding State, Converter={StaticResource StateToColorConverter}, Mode=OneWay}"
Text="{Binding SelectedValue, Mode=OneWay}"
TextWrapping="NoWrap" />
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsModified}" Value="True">
<Setter TargetName="DisplayText" Property="Foreground" Value="{DynamicResource TextPrimaryBrush}" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<DataTemplate x:Key="SettingValueEditTemplate">
<controls:SearchableComboBox
Margin="-2,-1,4,-1"
Padding="8,4"
HorizontalAlignment="Stretch"
behaviors:SettingValueValidationBehavior.Enabled="True"
Cursor=""
DeferSelectionUntilCommit="True"
IsEditable="True"
ItemsSource="{Binding ValueNameItems, Mode=OneWay}"
MaxDropDownHeight="400"
Placeholder="Search values..."
PreserveSelectionOnKeyboardFocus="True"
SyncSelectedItemToText="False"
Text="{Binding SelectedValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Validation.ErrorTemplate="{x:Null}">
<controls:SearchableComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Path
Width="12"
Height="12"
Margin="0,0,8,0"
Data="{Binding Source, Converter={StaticResource SettingMetaSourceToIconConverter}, Mode=OneWay}"
Fill="{DynamicResource TextSecondaryBrush}"
Stretch="Uniform" />
<TextBlock
Text="{Binding ValueName, Mode=OneWay}"
TextTrimming="CharacterEllipsis"
TextWrapping="NoWrap" />
</StackPanel>
</DataTemplate>
</controls:SearchableComboBox.ItemTemplate>
</controls:SearchableComboBox>
</DataTemplate>
</DataTemplate.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentControl
x:Name="ValueContent"
<Border
x:Name="ValueEditorAnchor"
Grid.Column="0"
Content="{Binding}"
ContentTemplate="{StaticResource SettingValueDisplayTemplate}" />
Margin="-2,-1,4,-1"
Background="Transparent" />
<ContentControl
x:Name="ValueEditorHost"
Grid.Column="0"
Margin="-2,-1,4,-1"
Visibility="Collapsed" />
<TextBlock
x:Name="DisplayText"
Grid.Column="0"
Margin="12,0"
VerticalAlignment="Center"
Foreground="{Binding State, Converter={StaticResource StateToColorConverter}, Mode=OneWay}"
Text="{Binding SelectedValue, Mode=OneWay}"
TextWrapping="NoWrap" />
<!-- Reset Button -->
<Button
x:Name="RestoreButton"
@@ -1389,7 +1397,8 @@
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}" Value="True">
<Setter TargetName="ValueContent" Property="ContentTemplate" Value="{StaticResource SettingValueEditTemplate}" />
<Setter TargetName="DisplayText" Property="Visibility" Value="Hidden" />
<Setter TargetName="ValueEditorHost" Property="Visibility" Value="Visible" />
</DataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
@@ -1402,6 +1411,7 @@
<Setter TargetName="RestoreButtonIcon" Property="Data" Value="{DynamicResource IconNvidia}" />
</MultiDataTrigger>
<DataTrigger Binding="{Binding IsModified}" Value="True">
<Setter TargetName="DisplayText" Property="Foreground" Value="{DynamicResource TextPrimaryBrush}" />
<Setter TargetName="RestoreButton" Property="Visibility" Value="Visible" />
<Setter TargetName="RestoreButton" Property="ToolTip" Value="Reset unsaved change" />
<Setter TargetName="RestoreButtonIcon" Property="Data" Value="{DynamicResource IconRestore}" />
@@ -1446,9 +1456,11 @@
</GroupStyle.ContainerStyle>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
</ListView>
</Grid>
</Grid>
<!-- Setting Description -->
<Border
Grid.Row="3"

View File

@@ -3,6 +3,7 @@ namespace nvidiaProfileInspector.UI.Views
using nvidiaProfileInspector;
using nvidiaProfileInspector.Native.WINAPI;
using nvidiaProfileInspector.Services;
using nvidiaProfileInspector.UI.Controls;
using nvidiaProfileInspector.UI.ViewModels;
using nvidiaProfileInspector.UI.Views.Dialogs;
using System;
@@ -26,6 +27,8 @@ namespace nvidiaProfileInspector.UI.Views
private readonly bool _showOnlyCustomizedSettings;
private HwndSource _windowSource;
private bool _mainWindowNativeDropRegistered;
private ContentControl _currentValueEditorHost;
private SearchableComboBox _sharedValueEditor;
public MainWindow(bool showOnlyCustomizedSettings = false, bool disableInitialScan = false)
{
@@ -38,6 +41,7 @@ namespace nvidiaProfileInspector.UI.Views
_viewModel.OnFocusFilter += () => FilterTextBox.Focus();
_themeManager.ThemeChanged += OnThemeChanged;
DataContext = _viewModel;
_sharedValueEditor = (SearchableComboBox)Resources["SharedValueEditorResource"];
if (_showOnlyCustomizedSettings)
_viewModel.FilterTypeIndex = 0;
@@ -45,6 +49,8 @@ namespace nvidiaProfileInspector.UI.Views
ApplyMockTitle();
SourceInitialized += MainWindow_SourceInitialized;
Dispatcher.BeginInvoke(new Action(PreloadAccessibilityAssembly), DispatcherPriority.ApplicationIdle);
SettingsListView.SelectionChanged += SettingsListView_SelectionChanged;
SettingsListView.LayoutUpdated += SettingsListView_LayoutUpdated;
}
private static void PreloadAccessibilityAssembly()
@@ -217,6 +223,7 @@ namespace nvidiaProfileInspector.UI.Views
{
RestoreWindowSettings();
await _viewModel.InitializeAsync(_disableInitialScan);
UpdateSharedValueEditorPlacement();
}
private void OnThemeChanged(string themeName)
@@ -252,11 +259,122 @@ namespace nvidiaProfileInspector.UI.Views
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
_themeManager.ThemeChanged -= OnThemeChanged;
SettingsListView.SelectionChanged -= SettingsListView_SelectionChanged;
SettingsListView.LayoutUpdated -= SettingsListView_LayoutUpdated;
var restoreBounds = WindowState == WindowState.Maximized ? RestoreBounds : new Rect(Left, Top, Width, Height);
_viewModel.SaveSettings(restoreBounds.Left, restoreBounds.Top, restoreBounds.Width, restoreBounds.Height, WindowState);
}
private void SettingsListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Dispatcher.BeginInvoke(new Action(UpdateSharedValueEditorPlacement), DispatcherPriority.Loaded);
}
private void SettingsListView_LayoutUpdated(object? sender, EventArgs e)
{
UpdateSharedValueEditorPlacement();
}
private void UpdateSharedValueEditorPlacement()
{
if (!IsLoaded || _viewModel.SelectedSetting == null)
{
HideSharedValueEditor();
return;
}
if (SettingsListView.ItemContainerGenerator.ContainerFromItem(_viewModel.SelectedSetting) is not ListViewItem selectedItem
|| !selectedItem.IsVisible)
{
HideSharedValueEditor();
return;
}
var anchor = FindDescendantByName<FrameworkElement>(selectedItem, "ValueEditorAnchor");
if (anchor == null || !anchor.IsVisible || anchor.ActualWidth <= 0 || anchor.ActualHeight <= 0)
{
HideSharedValueEditor();
return;
}
var host = FindDescendantByName<ContentControl>(selectedItem, "ValueEditorHost");
if (host == null)
{
HideSharedValueEditor();
return;
}
if (!ReferenceEquals(_currentValueEditorHost, host))
{
DetachSharedValueEditor();
host.Content = _sharedValueEditor;
_currentValueEditorHost = host;
}
_sharedValueEditor.Width = double.NaN;
_sharedValueEditor.ClearValue(FrameworkElement.HeightProperty);
_sharedValueEditor.HorizontalAlignment = HorizontalAlignment.Stretch;
_sharedValueEditor.VerticalAlignment = VerticalAlignment.Stretch;
_sharedValueEditor.FontWeight = selectedItem.FontWeight;
_sharedValueEditor.Visibility = Visibility.Visible;
ApplySharedValueEditorTypography(selectedItem);
_sharedValueEditor.UpdateLayout();
}
private void HideSharedValueEditor()
{
_sharedValueEditor.IsDropDownOpen = false;
_sharedValueEditor.Visibility = Visibility.Collapsed;
DetachSharedValueEditor();
}
private void DetachSharedValueEditor()
{
if (_currentValueEditorHost != null && ReferenceEquals(_currentValueEditorHost.Content, _sharedValueEditor))
_currentValueEditorHost.Content = null;
_currentValueEditorHost = null;
}
private void ApplySharedValueEditorTypography(ListViewItem selectedItem)
{
if (FindDescendantByName<TextBlock>(selectedItem, "DisplayText") is TextBlock displayText)
_sharedValueEditor.Foreground = displayText.Foreground;
if (_sharedValueEditor.Template?.FindName("PART_EditableTextBox", _sharedValueEditor) is TextBox editableTextBox)
{
editableTextBox.FontWeight = selectedItem.FontWeight;
editableTextBox.Foreground = _sharedValueEditor.Foreground;
}
if (_sharedValueEditor.Template?.FindName("ContentSite", _sharedValueEditor) is TextBlock contentSite)
{
contentSite.FontWeight = selectedItem.FontWeight;
contentSite.Foreground = _sharedValueEditor.Foreground;
}
}
private static T? FindDescendantByName<T>(DependencyObject root, string name) where T : FrameworkElement
{
if (root == null)
return null;
var childCount = VisualTreeHelper.GetChildrenCount(root);
for (var i = 0; i < childCount; i++)
{
var child = VisualTreeHelper.GetChild(root, i);
if (child is T element && string.Equals(element.Name, name, StringComparison.Ordinal))
return element;
var match = FindDescendantByName<T>(child, name);
if (match != null)
return match;
}
return null;
}
private void CustomSettingsOverrideChip_Click(object sender, RoutedEventArgs e)
{
MessageBoxEx.Show(