mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
UI - Added sidebar pinning, this closes #493
UI - Wrap long tooltips, this closes #480
This commit is contained in:
parent
bc8ac61388
commit
47dffc0fa0
@ -53,6 +53,13 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="WriteableBitmapEx" Version="1.6.5" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Include="Properties\DesignTimeResources.xaml" Condition="'$(DesignTime)'=='true' OR ('$(SolutionPath)'!='' AND Exists('$(SolutionPath)') AND '$(BuildingInsideVisualStudio)'!='true' AND '$(BuildingInsideExpressionBlend)'!='true')">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
<ContainsDesignTimeResources>true</ContainsDesignTimeResources>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="obj\x64\Debug\ColorPicker.g.cs" />
|
||||
<Compile Remove="obj\x64\Debug\ColorPicker.g.i.cs" />
|
||||
|
||||
@ -0,0 +1,8 @@
|
||||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.Teal.xaml" />
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Teal.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
@ -18,4 +18,17 @@
|
||||
</Grid>
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
|
||||
<Style TargetType="ToolTip" BasedOn="{StaticResource MaterialDesignToolTip}">
|
||||
<Style.Resources>
|
||||
<Style TargetType="ContentPresenter">
|
||||
<Style.Resources>
|
||||
<Style TargetType="TextBlock">
|
||||
<Setter Property="TextWrapping" Value="Wrap" />
|
||||
</Style>
|
||||
</Style.Resources>
|
||||
</Style>
|
||||
</Style.Resources>
|
||||
<Setter Property="MaxWidth" Value="500" />
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
@ -7,6 +7,7 @@
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:screens="clr-namespace:Artemis.UI.Screens"
|
||||
xmlns:mde="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||
mc:Ignorable="d"
|
||||
FadeContentIfInactive="False"
|
||||
Icon="/Resources/Images/Logo/logo-512.png"
|
||||
@ -48,6 +49,7 @@
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
<converters:InverseBooleanConverter x:Key="InverseBooleanConverter" />
|
||||
</mde:MaterialWindow.Resources>
|
||||
<materialDesign:DialogHost IsTabStop="False"
|
||||
Focusable="False"
|
||||
@ -55,25 +57,47 @@
|
||||
DialogTheme="Inherit"
|
||||
SnackbarMessageQueue="{Binding MainMessageQueue}">
|
||||
|
||||
<materialDesign:DrawerHost IsLeftDrawerOpen="{Binding SidebarViewModel.IsSidebarOpen}" >
|
||||
<materialDesign:DrawerHost IsLeftDrawerOpen="{Binding DockedSidebarViewModel.IsSidebarOpen}">
|
||||
<materialDesign:DrawerHost.LeftDrawerContent>
|
||||
<ContentControl s:View.Model="{Binding SidebarViewModel}" Width="280" />
|
||||
<ContentControl s:View.Model="{Binding DockedSidebarViewModel}"
|
||||
Width="280"
|
||||
Visibility="{Binding PinSidebar.Value, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}"/>
|
||||
</materialDesign:DrawerHost.LeftDrawerContent>
|
||||
<DockPanel>
|
||||
<Border DockPanel.Dock="Left"
|
||||
DockPanel.ZIndex="2"
|
||||
ClipToBounds="True"
|
||||
Background="{DynamicResource MaterialDesignToolBarBackground}"
|
||||
Visibility="{Binding PinSidebar.Value, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<ContentControl Grid.Column="0" s:View.Model="{Binding PinnedSidebarViewModel}" Width="280" />
|
||||
<Rectangle Grid.Column="1" Fill="DarkGray" Width="1" Margin="0 0 -1 0">
|
||||
<Rectangle.Effect>
|
||||
<DropShadowEffect ShadowDepth="0" BlurRadius="10" Color="{StaticResource MaterialDesignShadow}"/>
|
||||
</Rectangle.Effect>
|
||||
</Rectangle>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<mde:AppBar Type="Dense"
|
||||
IsNavigationDrawerOpen="{Binding SidebarViewModel.IsSidebarOpen, Mode=TwoWay}"
|
||||
IsNavigationDrawerOpen="{Binding DockedSidebarViewModel.IsSidebarOpen, Mode=TwoWay}"
|
||||
Title="{Binding ActiveItem.DisplayName}"
|
||||
ShowNavigationDrawerButton="True"
|
||||
DockPanel.Dock="Top">
|
||||
ShowNavigationDrawerButton="{Binding PinSidebar.Value, Converter={StaticResource InverseBooleanConverter}}"
|
||||
DockPanel.Dock="Top"
|
||||
DockPanel.ZIndex="1">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Text="{Binding FrameTime}"
|
||||
<TextBlock Text="{Binding FrameTime}"
|
||||
VerticalAlignment="Center"
|
||||
FontSize="14"
|
||||
Margin="10 0"
|
||||
ToolTip="The time the last frame took to render"/>
|
||||
FontSize="14"
|
||||
Margin="10 0"
|
||||
ToolTip="The time the last frame took to render" />
|
||||
|
||||
<!-- Bug: materialDesign:RippleAssist.RippleOnTop doesn't look as nice but otherwise it doesn't work at all, not sure why -->
|
||||
<Button Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
<Button Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="Open debugger"
|
||||
Command="{s:Action ShowDebugger}"
|
||||
materialDesign:RippleAssist.RippleOnTop="True">
|
||||
@ -84,7 +108,7 @@
|
||||
|
||||
<Grid>
|
||||
<ContentControl s:View.Model="{Binding ActiveItem}" Style="{StaticResource InitializingFade}" />
|
||||
<materialDesign:Snackbar x:Name="MainSnackbar"
|
||||
<materialDesign:Snackbar x:Name="MainSnackbar"
|
||||
MessageQueue="{Binding MainMessageQueue}"
|
||||
materialDesign:SnackbarMessage.InlineActionButtonMaxHeight="80"
|
||||
materialDesign:SnackbarMessage.ContentMaxHeight="200" />
|
||||
|
||||
@ -28,6 +28,7 @@ namespace Artemis.UI.Screens
|
||||
private readonly IDebugService _debugService;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly Timer _frameTimeUpdateTimer;
|
||||
private readonly SidebarViewModel _sidebarViewModel;
|
||||
private readonly ISnackbarMessageQueue _snackbarMessageQueue;
|
||||
private readonly ThemeWatcher _themeWatcher;
|
||||
private readonly PluginSetting<WindowSize> _windowSize;
|
||||
@ -35,6 +36,7 @@ namespace Artemis.UI.Screens
|
||||
private string _frameTime;
|
||||
private bool _lostFocus;
|
||||
private ISnackbarMessageQueue _mainMessageQueue;
|
||||
private MaterialWindow _window;
|
||||
private string _windowTitle;
|
||||
|
||||
public RootViewModel(
|
||||
@ -46,12 +48,12 @@ namespace Artemis.UI.Screens
|
||||
ISnackbarMessageQueue snackbarMessageQueue,
|
||||
SidebarViewModel sidebarViewModel)
|
||||
{
|
||||
SidebarViewModel = sidebarViewModel;
|
||||
_eventAggregator = eventAggregator;
|
||||
_coreService = coreService;
|
||||
_debugService = debugService;
|
||||
_builtInRegistrationService = builtInRegistrationService;
|
||||
_snackbarMessageQueue = snackbarMessageQueue;
|
||||
_sidebarViewModel = sidebarViewModel;
|
||||
|
||||
_frameTimeUpdateTimer = new Timer(500);
|
||||
|
||||
@ -61,14 +63,19 @@ namespace Artemis.UI.Screens
|
||||
_themeWatcher = new ThemeWatcher();
|
||||
ApplyColorSchemeSetting();
|
||||
|
||||
ActiveItem = SidebarViewModel.SelectedItem;
|
||||
ActiveItem = sidebarViewModel.SelectedItem;
|
||||
ActiveItemReady = true;
|
||||
|
||||
PinSidebar = settingsService.GetSetting("UI.PinSidebar", false);
|
||||
|
||||
AssemblyInformationalVersionAttribute versionAttribute = typeof(RootViewModel).Assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>();
|
||||
WindowTitle = $"Artemis {versionAttribute?.InformationalVersion}";
|
||||
}
|
||||
|
||||
public SidebarViewModel SidebarViewModel { get; }
|
||||
public PluginSetting<bool> PinSidebar { get; }
|
||||
|
||||
// Just a litte trick to get the non-active variant completely removed from XAML (that should probably be done in the view)
|
||||
public SidebarViewModel PinnedSidebarViewModel => PinSidebar.Value ? _sidebarViewModel : null;
|
||||
public SidebarViewModel DockedSidebarViewModel => PinSidebar.Value ? null : _sidebarViewModel;
|
||||
|
||||
public ISnackbarMessageQueue MainMessageQueue
|
||||
{
|
||||
@ -138,6 +145,13 @@ namespace Artemis.UI.Screens
|
||||
_eventAggregator.Publish(new MainWindowMouseEvent(sender, false, e));
|
||||
}
|
||||
|
||||
private void UpdateSidebarPinState()
|
||||
{
|
||||
_sidebarViewModel.IsSidebarOpen = true;
|
||||
|
||||
NotifyOfPropertyChange(nameof(PinnedSidebarViewModel));
|
||||
NotifyOfPropertyChange(nameof(DockedSidebarViewModel));
|
||||
}
|
||||
|
||||
private void UpdateFrameTime()
|
||||
{
|
||||
@ -146,18 +160,25 @@ namespace Artemis.UI.Screens
|
||||
|
||||
private void SidebarViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(SidebarViewModel.SelectedItem) && ActiveItem != SidebarViewModel.SelectedItem)
|
||||
if (e.PropertyName == nameof(_sidebarViewModel.SelectedItem) && ActiveItem != _sidebarViewModel.SelectedItem)
|
||||
{
|
||||
SidebarViewModel.IsSidebarOpen = false;
|
||||
// Unless the sidebar is pinned, close it upon selecting an item
|
||||
if (!PinSidebar.Value)
|
||||
_sidebarViewModel.IsSidebarOpen = false;
|
||||
|
||||
// Don't do a fade when selecting a module because the editor is so bulky the animation slows things down
|
||||
if (!(SidebarViewModel.SelectedItem is ModuleRootViewModel))
|
||||
if (!(_sidebarViewModel.SelectedItem is ModuleRootViewModel))
|
||||
ActiveItemReady = false;
|
||||
|
||||
// Allow the menu to close, it's slower but feels more responsive, funny how that works right
|
||||
Execute.PostToUIThreadAsync(async () =>
|
||||
{
|
||||
await Task.Delay(400);
|
||||
ActiveItem = SidebarViewModel.SelectedItem;
|
||||
if (PinSidebar.Value)
|
||||
await Task.Delay(200);
|
||||
else
|
||||
await Task.Delay(400);
|
||||
|
||||
ActiveItem = _sidebarViewModel.SelectedItem;
|
||||
ActiveItemReady = true;
|
||||
});
|
||||
}
|
||||
@ -208,6 +229,11 @@ namespace Artemis.UI.Screens
|
||||
ApplyColorSchemeSetting();
|
||||
}
|
||||
|
||||
private void PinSidebarOnSettingChanged(object sender, EventArgs e)
|
||||
{
|
||||
UpdateSidebarPinState();
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -236,7 +262,7 @@ namespace Artemis.UI.Screens
|
||||
base.OnViewLoaded();
|
||||
}
|
||||
|
||||
protected override void OnActivate()
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
MainMessageQueue = _snackbarMessageQueue;
|
||||
UpdateFrameTime();
|
||||
@ -248,14 +274,17 @@ namespace Artemis.UI.Screens
|
||||
_frameTimeUpdateTimer.Elapsed += OnFrameTimeUpdateTimerOnElapsed;
|
||||
_colorScheme.SettingChanged += ColorSchemeOnSettingChanged;
|
||||
_themeWatcher.ThemeChanged += ThemeWatcherOnThemeChanged;
|
||||
SidebarViewModel.PropertyChanged += SidebarViewModelOnPropertyChanged;
|
||||
_sidebarViewModel.PropertyChanged += SidebarViewModelOnPropertyChanged;
|
||||
PinSidebar.SettingChanged += PinSidebarOnSettingChanged;
|
||||
|
||||
_frameTimeUpdateTimer.Start();
|
||||
|
||||
base.OnActivate();
|
||||
_window = (MaterialWindow) View;
|
||||
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
protected override void OnDeactivate()
|
||||
protected override void OnClose()
|
||||
{
|
||||
// Ensure no element with focus can leak, if we don't do this the root VM is retained by Window.EffectiveValues
|
||||
// https://stackoverflow.com/a/30864434
|
||||
@ -264,22 +293,17 @@ namespace Artemis.UI.Screens
|
||||
MainMessageQueue = null;
|
||||
_frameTimeUpdateTimer.Stop();
|
||||
|
||||
MaterialWindow window = (MaterialWindow) View;
|
||||
_windowSize.Value ??= new WindowSize();
|
||||
_windowSize.Value.ApplyFromWindow(window);
|
||||
_windowSize.Value.ApplyFromWindow(_window);
|
||||
_windowSize.Save();
|
||||
|
||||
_frameTimeUpdateTimer.Elapsed -= OnFrameTimeUpdateTimerOnElapsed;
|
||||
_colorScheme.SettingChanged -= ColorSchemeOnSettingChanged;
|
||||
_themeWatcher.ThemeChanged -= ThemeWatcherOnThemeChanged;
|
||||
SidebarViewModel.PropertyChanged -= SidebarViewModelOnPropertyChanged;
|
||||
_sidebarViewModel.PropertyChanged -= SidebarViewModelOnPropertyChanged;
|
||||
PinSidebar.SettingChanged -= PinSidebarOnSettingChanged;
|
||||
|
||||
base.OnDeactivate();
|
||||
}
|
||||
|
||||
protected override void OnClose()
|
||||
{
|
||||
SidebarViewModel.Dispose();
|
||||
_sidebarViewModel.Dispose();
|
||||
|
||||
// Lets force the GC to run after closing the window so it is obvious to users watching task manager
|
||||
// that closing the UI will decrease the memory footprint of the application.
|
||||
@ -291,6 +315,7 @@ namespace Artemis.UI.Screens
|
||||
GC.Collect();
|
||||
});
|
||||
|
||||
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
|
||||
@ -23,6 +23,23 @@
|
||||
Source="/Resources/Images/Sidebar/sidebar-header.png"
|
||||
Stretch="UniformToFill"
|
||||
VerticalAlignment="Top" Height="120" />
|
||||
|
||||
<ToggleButton Grid.Row="0"
|
||||
Style="{StaticResource MaterialDesignSwitchLightToggleButton}"
|
||||
ToolTip="Pin sidebar"
|
||||
HorizontalAlignment="Right"
|
||||
IsChecked="{Binding PinSidebar.Value, Delay=300}"
|
||||
Margin="10 0">
|
||||
<materialDesign:PackIcon Kind="Pin" RenderTransformOrigin=".5,.5">
|
||||
<materialDesign:PackIcon.RenderTransform>
|
||||
<RotateTransform Angle="45" />
|
||||
</materialDesign:PackIcon.RenderTransform>
|
||||
</materialDesign:PackIcon>
|
||||
<materialDesign:ToggleButtonAssist.OnContent>
|
||||
<materialDesign:PackIcon Kind="Pin" />
|
||||
</materialDesign:ToggleButtonAssist.OnContent>
|
||||
</ToggleButton>
|
||||
|
||||
<TextBlock Grid.Row="1"
|
||||
Style="{StaticResource MaterialDesignHeadline6TextBlock}"
|
||||
Foreground="{StaticResource PrimaryHueDarkForegroundBrush}"
|
||||
|
||||
@ -26,6 +26,7 @@ namespace Artemis.UI.Screens.Sidebar
|
||||
{
|
||||
private readonly Timer _activeModulesUpdateTimer;
|
||||
private readonly IKernel _kernel;
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly IModuleVmFactory _moduleVmFactory;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private string _activeModules;
|
||||
@ -34,14 +35,17 @@ namespace Artemis.UI.Screens.Sidebar
|
||||
private BindableCollection<INavigationItem> _sidebarItems;
|
||||
private Dictionary<INavigationItem, Module> _sidebarModules;
|
||||
|
||||
public SidebarViewModel(IKernel kernel, IEventAggregator eventAggregator, IModuleVmFactory moduleVmFactory, IPluginManagementService pluginManagementService)
|
||||
public SidebarViewModel(IKernel kernel, ISettingsService settingsService, IEventAggregator eventAggregator, IModuleVmFactory moduleVmFactory, IPluginManagementService pluginManagementService)
|
||||
{
|
||||
_kernel = kernel;
|
||||
_settingsService = settingsService;
|
||||
_moduleVmFactory = moduleVmFactory;
|
||||
_pluginManagementService = pluginManagementService;
|
||||
|
||||
SidebarModules = new Dictionary<INavigationItem, Module>();
|
||||
SidebarItems = new BindableCollection<INavigationItem>();
|
||||
PinSidebar = settingsService.GetSetting("UI.PinSidebar", false);
|
||||
PinSidebar.AutoSave = true;
|
||||
|
||||
_activeModulesUpdateTimer = new Timer(1000);
|
||||
_activeModulesUpdateTimer.Start();
|
||||
@ -54,6 +58,8 @@ namespace Artemis.UI.Screens.Sidebar
|
||||
eventAggregator.Subscribe(this);
|
||||
}
|
||||
|
||||
public PluginSetting<bool> PinSidebar { get; }
|
||||
|
||||
public BindableCollection<INavigationItem> SidebarItems
|
||||
{
|
||||
get => _sidebarItems;
|
||||
@ -108,6 +114,10 @@ namespace Artemis.UI.Screens.Sidebar
|
||||
foreach (Module module in modules)
|
||||
AddModule(module);
|
||||
|
||||
// Set the sidebar as open if it's pinned
|
||||
if (PinSidebar.Value)
|
||||
IsSidebarOpen = true;
|
||||
|
||||
// Select the top item, which will be one of the defaults
|
||||
Task.Run(() => SelectSidebarItem(SidebarItems[0]));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user