Skip to content

Commit

Permalink
settings UI tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
retailcoder committed Mar 17, 2024
1 parent b786675 commit b88e8d5
Show file tree
Hide file tree
Showing 26 changed files with 445 additions and 130 deletions.
104 changes: 83 additions & 21 deletions Client/Rubberduck.UI/Converters/WrapPanelItemWidthConverter.cs
Original file line number Diff line number Diff line change
@@ -1,50 +1,112 @@
using Rubberduck.UI.Shared.Settings.Abstract;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;

namespace Rubberduck.UI.Converters
{
public class WrapPanelItemWidthConverter : IValueConverter
public class WrapPanelItemWidthMultiConverter : IMultiValueConverter
{
public double MinItemWidth { get; set; } = 300;
public double MaxItemWidth { get; set; } = 720;
public double Margin { get; set; } = 10;
public double SmallItemWidth { get; set; } = 380;
public double LargeItemWidth { get; set; } = 720;

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
var panelWidth = (double)value;
var items = ((IEnumerable<ISettingViewModel>)((CollectionViewSource)parameter)?.Source)?.Count() ?? 0;
if (items > 1)
var fullPanelWidth = (double)values[0] - Margin;
var items = (IEnumerable<ISettingViewModel>)values[1];
if (values.Length > 2)
{
if (panelWidth <= MinItemWidth)
{
return MinItemWidth;
}
return fullPanelWidth;
}

var nonGroupingItems = items.Except(items.OfType<ISettingGroupViewModel>()).ToArray();
var isSingleItem = nonGroupingItems.Length == 1;

if (isSingleItem || fullPanelWidth <= SmallItemWidth)
{
return fullPanelWidth;
}

if (nonGroupingItems.Length >= 4 && fullPanelWidth >= 4 * SmallItemWidth)
{
return fullPanelWidth / 4d;
}

if (nonGroupingItems.Length >= 3 && fullPanelWidth >= 3 * SmallItemWidth)
{
return fullPanelWidth / 3d;
}

if (nonGroupingItems.Length >= 2 && fullPanelWidth >= 2 * SmallItemWidth)
{
return fullPanelWidth / 2d;
}

var maxWidthColumns = panelWidth / MaxItemWidth;
if (maxWidthColumns > 2)
if (nonGroupingItems.Length >= 3 && nonGroupingItems.Length % 3 == 0)
{
var idealWidth = (int)(fullPanelWidth / 3d);
if (idealWidth < SmallItemWidth)
{
return panelWidth / (int)maxWidthColumns;
return fullPanelWidth;
}
return idealWidth;
}

var minWidthColumns = panelWidth / MinItemWidth;
if (minWidthColumns > 1.5)
if (nonGroupingItems.Length >= 2 && nonGroupingItems.Length % 2 == 0)
{
var idealWidth = (int)(fullPanelWidth / 2d);
if (idealWidth < SmallItemWidth)
{
return panelWidth / (int)minWidthColumns;
return fullPanelWidth;
}
return idealWidth;
}

return fullPanelWidth;
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}

public class WrapPanelItemWidthConverter : IValueConverter
{
public double MinItemWidth { get; set; } = 380;
public double MaxItemWidth { get; set; } = 720;

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var panelWidth = (double)value;
if (panelWidth <= MinItemWidth)
{
return MinItemWidth;
}

var maxWidthColumns = panelWidth / MaxItemWidth;
if (maxWidthColumns > 2)
{
return panelWidth / (int)maxWidthColumns - 32;
}

var minWidthColumns = panelWidth / MinItemWidth;
if (minWidthColumns > 2)
{
return panelWidth / (int)minWidthColumns - 32;
}


return panelWidth;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value;
throw new NotImplementedException();
}
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions Client/Rubberduck.UI/Rubberduck.UI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,8 @@
<None Remove="Resources\FontAwesome\square-xmark-solid-red.png" />
<None Remove="Resources\FontAwesome\square-xmark-solid.png" />
<None Remove="Resources\FontAwesome\thumbtack-solid.png" />
<None Remove="Resources\FontAwesome\toggle-off-solid.png" />
<None Remove="Resources\FontAwesome\toggle-on-solid.png" />
<None Remove="Resources\FontAwesome\window-maximize-regular.png" />
<None Remove="Resources\FontAwesome\window-minimize-regular.png" />
<None Remove="Resources\FontAwesome\window-restore-regular.png" />
Expand Down Expand Up @@ -258,6 +260,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="AsyncAwaitBestPractices" Version="7.0.0" />
<PackageReference Include="AvalonEdit" Version="6.3.0.90" />
<PackageReference Include="Dragablz" Version="0.0.3.234" />
<PackageReference Include="MdXaml" Version="1.21.0" />
Expand Down Expand Up @@ -469,6 +472,8 @@
<Resource Include="Resources\FontAwesome\square-xmark-solid-red.png" />
<Resource Include="Resources\FontAwesome\square-xmark-solid.png" />
<Resource Include="Resources\FontAwesome\thumbtack-solid.png" />
<Resource Include="Resources\FontAwesome\toggle-off-solid.png" />
<Resource Include="Resources\FontAwesome\toggle-on-solid.png" />
<Resource Include="Resources\FontAwesome\window-maximize-regular.png" />
<Resource Include="Resources\FontAwesome\window-minimize-regular.png" />
<Resource Include="Resources\FontAwesome\window-restore-regular.png" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public ISettingGroupViewModel CreateViewModel(TypedSettingGroup settingGroup)
{
if (settingGroup is RubberduckSettings root)
{
var items = root.TypedValue.OfType<TypedSettingGroup>().Select(e => CreateViewModel(e)).ToList();
var items = root.TypedValue.OfType<TypedSettingGroup>().Select(CreateViewModel).ToList();
return new SettingGroupViewModel(root, items);
}
else
Expand Down
26 changes: 25 additions & 1 deletion Client/Rubberduck.UI/Services/Settings/SettingsDialogService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Rubberduck.InternalApi.Settings;
using Rubberduck.InternalApi.Settings.Model;
using Rubberduck.InternalApi.Services;
using Rubberduck.UI.Shared.Settings.Abstract;

namespace Rubberduck.UI.Services.Settings
{
Expand Down Expand Up @@ -46,6 +47,29 @@ protected override SettingsWindowViewModel CreateViewModel(RubberduckSettings se
return vm;
}

private ISettingGroupViewModel GetSettingGroup(string key)
{
var flattened = Settings.Flatten();

// if the key is a top-level setting group, we return it immediately
// because there is no need to figure out the parent.
var groups = Settings.TypedValue.OfType<TypedSettingGroup>().ToDictionary(e => e.Key, e => e);
if (groups.TryGetValue(key, out var settingGroup))
{
return _vmFactory.CreateViewModel(settingGroup);
}

// first find the key we're looking for
var item = flattened.Single(e => e.Key == key);

// now find its parent
var parent = flattened.OfType<TypedSettingGroup>().SingleOrDefault(e => e.TypedValue.Any(e => e.Key == key));
var parentViewModel = (ISettingGroupViewModel)CreateViewModel(Settings, _actionsProvider);

// push parent to nav stack, then push vm
return parentViewModel;
}

public SettingsWindowViewModel ShowDialog(string key)
{
SettingsWindowViewModel viewModel = default!;
Expand All @@ -60,7 +84,7 @@ public SettingsWindowViewModel ShowDialog(string key)
?? throw new InvalidOperationException($"CreateViewModel returned null.");

var settingGroup = viewModel.Settings.Items.Select(e => (VM: e, e.Key)).SingleOrDefault(e => e.Key == key).VM;
viewModel.Selection = settingGroup;
viewModel.Selection = settingGroup ?? viewModel.Settings;

view = _factory.Create(viewModel)
?? throw new InvalidOperationException($"ViewFactory.Create returned null.");
Expand Down
25 changes: 21 additions & 4 deletions Client/Rubberduck.UI/Services/Settings/SettingsWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Rubberduck.UI.Shared.Settings.Abstract;
using Rubberduck.UI.Windows;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;

Expand Down Expand Up @@ -36,10 +37,10 @@ public SettingsWindowViewModel(UIServiceHelper service, MessageActionCommand[] a
}
});

CommandBindings = new CommandBinding[]
{
CommandBindings =
[
new(NavigationCommands.Search, DialogCommandHandlers.BrowseLocationCommandBinding_Executed, DialogCommandHandlers.BrowseLocationCommandBinding_CanExecute),
};
];
}

public override IEnumerable<CommandBinding> CommandBindings { get; }
Expand All @@ -48,9 +49,25 @@ public SettingsWindowViewModel(UIServiceHelper service, MessageActionCommand[] a

public ICommand ExpandSettingGroupCommand { get; }

private Stack<ISettingViewModel> _previous = [];
private void ExecuteExpandSettingGroupCommand(ISettingGroupViewModel model)
{
Selection = model;
if (model.IsExpanded)
{
_previous.Push(Selection);
Selection = model;
}
else
{
if (_previous.TryPop(out var previous))
{
Selection = previous;
}
else
{
Selection = _settings.Items.FirstOrDefault()!;
}
}
}

private ISettingGroupViewModel _settings;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Rubberduck.InternalApi.Settings.Model;
using Rubberduck.Resources.v3;
using System;
using System.Collections.Generic;

Expand All @@ -15,9 +16,10 @@ protected EnumValueSettingViewModel(RubberduckSetting setting)
}

public SettingDataType SettingDataType => _setting.SettingDataType;
public bool IsSettingGroup => false;
public string Key => _setting.Key;
public string Name => _setting.Key; // TODO fetch from resources
public string Description => _setting.Key; // TODO fetch from resources
public string Name => SettingsUI.ResourceManager.GetString($"{_setting.Key}_Title")!;
public string Description => SettingsUI.ResourceManager.GetString($"{_setting.Key}_Description")!;
public SettingTags Tags => _setting.Tags;

private bool _isEnabled;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ namespace Rubberduck.UI.Shared.Settings.Abstract
{
public interface ISettingGroupViewModel : ISettingViewModel
{
public ObservableCollection<ISettingViewModel> Items { get; }
ObservableCollection<ISettingViewModel> Items { get; }
bool IsExpanded { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace Rubberduck.UI.Shared.Settings.Abstract
{
public interface ISettingViewModel : INotifyPropertyChanged
{
bool IsSettingGroup { get; }
string Key { get; }
SettingDataType SettingDataType { get; }
string Name { get; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ protected SettingViewModel(TypedRubberduckSetting<TValue> setting)
public string Description => SettingsUI.ResourceManager.GetString($"{_setting.Key}_Description") ?? $"[missing key:{_setting.Key}_Description]";

public SettingTags Tags => _setting.Tags;
public bool IsSettingGroup => false;
public bool IsReadOnlyRecommended => Tags.HasFlag(SettingTags.ReadOnlyRecommended);
public bool IsAdvancedSetting => Tags.HasFlag(SettingTags.Advanced);
public bool IsExperimental => Tags.HasFlag(SettingTags.Experimental);
Expand Down
6 changes: 4 additions & 2 deletions Client/Rubberduck.UI/Shared/Settings/SettingGroupViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ internal SettingGroupViewModel()
public SettingGroupViewModel(TypedSettingGroup settingGroup, IEnumerable<ISettingViewModel> items)
{
_settingGroup = settingGroup;
Items = new ObservableCollection<ISettingViewModel>(items);
Items = new ObservableCollection<ISettingViewModel>(items.OrderBy(e => e.IsSettingGroup));
IsEnabled = !_settingGroup.Tags.HasFlag(SettingTags.ReadOnlyRecommended);
}

Expand All @@ -32,14 +32,16 @@ public SettingGroupViewModel(TypedRubberduckSetting<BooleanRubberduckSetting[]>

public ObservableCollection<ISettingViewModel> Items { get; init; }

public bool IsSettingGroup => true;

public SettingDataType SettingDataType => _settingGroup.SettingDataType;
public string Key => _settingGroup.Key;
public string Name => SettingsUI.ResourceManager.GetString($"{_settingGroup.Key}_Title") ?? $"[missing key:{_settingGroup.Key}_Title]";

public string Description => SettingsUI.ResourceManager.GetString($"{_settingGroup.Key}_Description") ?? $"[missing key:{_settingGroup.Key}_Description]";

public SettingTags Tags => _settingGroup.Tags;
public bool IsReadOnlyRecommended => Tags.HasFlag(SettingTags.ReadOnlyRecommended);
public bool IsReadOnlyRecommended => !IsExpanded && Tags.HasFlag(SettingTags.ReadOnlyRecommended);
public bool IsAdvancedSetting => Tags.HasFlag(SettingTags.Advanced);
public bool IsExperimental => Tags.HasFlag(SettingTags.Experimental);

Expand Down
12 changes: 6 additions & 6 deletions Client/Rubberduck.UI/Shared/Settings/SettingsWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,12 @@
</ListView>
</Border>


<templates:SettingGroupControl Grid.Column="1"
DataContext="{Binding Selection}"
Background="{DynamicResource ThemeWhiteLightColorBrush75}"
BorderThickness="1" BorderBrush="{DynamicResource ThemeWhiteDarkColorBrush}"
Margin="5"/>
<Border Grid.Column="1"
BorderThickness="1" BorderBrush="{DynamicResource ThemeWhiteDarkColorBrush}"
Background="{DynamicResource ThemeWhiteLightColorBrush65}"
CornerRadius="4" Margin="5" Padding="10">
<templates:SettingGroupControl DataContext="{Binding Selection}" />
</Border>
</Grid>
</shell:ThunderFrame>
<Thumb Grid.Row="1" HorizontalAlignment="Right" IsEnabled="True" IsHitTestVisible="True" WindowChrome.IsHitTestVisibleInChrome="True"
Expand Down
Loading

0 comments on commit b88e8d5

Please sign in to comment.