1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

UI polish

This commit is contained in:
SpoinkyNL 2016-05-30 23:53:53 +02:00
parent b01f9485ae
commit eb59ddc816
11 changed files with 194 additions and 76 deletions

View File

@ -6,11 +6,13 @@ using System.Xml.Serialization;
using Artemis.DeviceProviders;
using Artemis.Models;
using Artemis.Models.Profiles;
using NLog;
namespace Artemis.DAL
{
public static class ProfileProvider
{
private static Logger _logger = LogManager.GetCurrentClassLogger();
private static readonly string ProfileFolder =
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Artemis\profiles";
@ -56,9 +58,12 @@ namespace Artemis.DAL
Directory.CreateDirectory(path);
var serializer = new XmlSerializer(typeof(ProfileModel));
using (var file = new StreamWriter(path + $@"\{prof.Name}.xml"))
// Could use a StreamWriter but should serializing fail this method doesn't ruin the existing XML file
using (var xml = new StringWriter())
{
serializer.Serialize(file, prof);
serializer.Serialize(xml, prof);
File.WriteAllText(path + $@"\{prof.Name}.xml", xml.ToString());
}
}
@ -71,16 +76,23 @@ namespace Artemis.DAL
var profilePaths = Directory.GetFiles(ProfileFolder, "*.xml", SearchOption.AllDirectories);
// Parse the JSON files into objects and add them if they are valid
// TODO: Invalid file handling
var deserializer = new XmlSerializer(typeof(ProfileModel));
foreach (var path in profilePaths)
{
using (var file = new StreamReader(path))
try
{
var prof = (ProfileModel) deserializer.Deserialize(file);
if (prof.GameName?.Length > 1 && prof.KeyboardName?.Length > 1 && prof.Name?.Length > 1)
profiles.Add(prof);
using (var file = new StreamReader(path))
{
var prof = (ProfileModel)deserializer.Deserialize(file);
if (prof.GameName?.Length > 1 && prof.KeyboardName?.Length > 1 && prof.Name?.Length > 1)
profiles.Add(prof);
}
}
catch (InvalidOperationException e)
{
_logger.Error("Failed to load profile: {0} - {1}", path, e.InnerException.Message);
}
}
return profiles;

View File

@ -59,12 +59,11 @@ namespace Artemis.Models.Profiles
}
else
appliedProperties = GeneralHelpers.Clone(Properties);
// Update animations on layer types that support them
if ((LayerType == LayerType.Keyboard || LayerType == LayerType.KeyboardGif) && updateAnimations)
if ((LayerType == LayerType.Keyboard || LayerType == LayerType.KeyboardGif))
{
AnimationUpdater.UpdateAnimation((KeyboardPropertiesModel) Properties,
(KeyboardPropertiesModel) appliedProperties);
AnimationUpdater.UpdateAnimation((KeyboardPropertiesModel) Properties, (KeyboardPropertiesModel) appliedProperties, updateAnimations);
}
switch (LayerType)
@ -195,6 +194,27 @@ namespace Artemis.Models.Profiles
}
#endregion
public static LayerModel CreateLayer()
{
return new LayerModel
{
Name = "New layer",
Enabled = true,
Order = -1,
LayerType = LayerType.Keyboard,
Properties = new KeyboardPropertiesModel
{
Brush = new SolidColorBrush(ColorHelpers.GetRandomRainbowMediaColor()),
Animation = LayerAnimation.None,
Height = 1,
Width = 1,
X = 0,
Y = 0,
Opacity = 1
}
};
}
}
public enum LayerType

View File

@ -28,6 +28,7 @@ namespace Artemis.Models.Profiles
public string Name { get; set; }
public string KeyboardName { get; set; }
public string GameName { get; set; }
public bool IsDefault { get; set; }
[XmlIgnore]
public DrawingVisual DrawingVisual { get; set; }
@ -58,36 +59,6 @@ namespace Artemis.Models.Profiles
}
}
/// <summary>
/// Adds a new layer with default settings to the profile
/// </summary>
/// <returns>The newly added layer</returns>
public LayerModel AddLayer()
{
var layer = new LayerModel
{
Name = "New layer",
Enabled = true,
Order = -1,
LayerType = LayerType.Keyboard,
Properties = new KeyboardPropertiesModel
{
Brush = new SolidColorBrush(ColorHelpers.GetRandomRainbowMediaColor()),
Animation = LayerAnimation.None,
Height = 1,
Width = 1,
X = 0,
Y = 0,
Opacity = 1
}
};
Layers.Add(layer);
FixOrder();
return layer;
}
public void FixOrder()
{
Layers.Sort(l => l.Order);

View File

@ -24,6 +24,8 @@ namespace Artemis.Models.Profiles.Properties
public double AnimationSpeed { get; set; }
public string GifFile { get; set; }
public List<DynamicPropertiesModel> DynamicProperties { get; set; }
[XmlIgnore]
public double AnimationProgress { get; set; }
public Rect GetRect(int scale = 4)

View File

@ -22,6 +22,7 @@
using System;
using System.Threading.Tasks;
using MahApps.Metro.Controls.Dialogs;
namespace Artemis.Services
{
@ -41,7 +42,7 @@ namespace Artemis.Services
public abstract bool ShowOpenDialog(out string path, string defaultExt, string filter, string initialDir = null);
public abstract Task<string> ShowInputDialog(string title, string message);
public abstract Task<string> ShowInputDialog(string title, string message, MetroDialogSettings settings = null);
public abstract Task<bool?> ShowQuestionMessageBox(string title, string message);
}

View File

@ -75,12 +75,12 @@ namespace Artemis.Services
}
}
public override Task<string> ShowInputDialog(string title, string message)
public override Task<string> ShowInputDialog(string title, string message, MetroDialogSettings settings = null)
{
if (GetActiveWindow() == null)
return null;
return GetActiveWindow().ShowInputAsync(title, message);
return GetActiveWindow().ShowInputAsync(title, message, settings);
}
public override bool ShowOpenDialog(out string path, string defaultExt, string filter, string initialDir = null)

View File

@ -4,10 +4,11 @@ namespace Artemis.Utilities.Layers
{
public static class AnimationUpdater
{
public static void UpdateAnimation(KeyboardPropertiesModel properties, KeyboardPropertiesModel appliedProperties)
public static void UpdateAnimation(KeyboardPropertiesModel properties, KeyboardPropertiesModel appliedProperties, bool updateAnimations)
{
const int scale = 4;
var animateProperties = properties.Contain ? appliedProperties : properties;
appliedProperties.AnimationProgress = properties.AnimationProgress;
var progress = appliedProperties.AnimationProgress;
// Horizontal sliding
@ -40,8 +41,10 @@ namespace Artemis.Utilities.Layers
}
appliedProperties.AnimationProgress = progress;
// Store the animation progress in the actual model for the next frame
properties.AnimationProgress = progress;
// If not previewing, store the animation progress in the actual model for the next frame
if (updateAnimations)
properties.AnimationProgress = progress;
}
}
}

View File

@ -6,7 +6,10 @@ using Artemis.Managers;
using Artemis.Settings;
using Caliburn.Micro;
using MahApps.Metro.Controls;
using Ninject.Extensions.Logging;
using NLog;
using NLog.Config;
using NLog.Targets;
using ILogger = Ninject.Extensions.Logging.ILogger;
namespace Artemis.ViewModels.Flyouts
{
@ -15,6 +18,7 @@ namespace Artemis.ViewModels.Flyouts
{
private readonly ILogger _logger;
private string _activeEffectName;
private bool _enableDebug;
private GeneralSettings _generalSettings;
private string _selectedKeyboardProvider;
@ -29,6 +33,20 @@ namespace Artemis.ViewModels.Flyouts
PropertyChanged += KeyboardUpdater;
events.Subscribe(this);
ApplyLogging();
}
public MainManager MainManager { get; set; }
public bool EnableDebug
{
get { return _enableDebug; }
set
{
if (value == _enableDebug) return;
_enableDebug = value;
NotifyOfPropertyChange(() => EnableDebug);
}
}
public GeneralSettings GeneralSettings
@ -42,8 +60,6 @@ namespace Artemis.ViewModels.Flyouts
}
}
public MainManager MainManager { get; set; }
public BindableCollection<string> KeyboardProviders
{
get
@ -100,6 +116,27 @@ namespace Artemis.ViewModels.Flyouts
NotifyOfPropertyChange(() => Enabled);
}
// TODO https://github.com/ninject/Ninject.Extensions.Logging/issues/35
private void ApplyLogging()
{
var c = NLog.LogManager.Configuration;
var file = c.FindTargetByName("file") as FileTarget;
if (file == null)
return;
var rule = c.LoggingRules.FirstOrDefault(r => r.Targets.Contains(file));
if (rule == null)
return;
if (EnableDebug)
rule.EnableLoggingForLevel(LogLevel.Debug);
else
rule.DisableLoggingForLevel(LogLevel.Debug);
NLog.LogManager.ReconfigExistingLoggers();
_logger.Info("Set debug logging to: {0}", EnableDebug);
}
/// <summary>
/// Takes proper action when the selected keyboard is changed in the UI
/// </summary>

View File

@ -120,6 +120,9 @@ namespace Artemis.ViewModels.Profiles
if (e.PropertyName != "LayerType")
return;
// Store the brush in case the user wants to reuse it
var oldBrush = LayerPropertiesViewModel?.GetAppliedProperties().Brush;
// Update the model
if (Layer.LayerType != LayerType)
{
@ -127,6 +130,9 @@ namespace Artemis.ViewModels.Profiles
Layer.SetupProperties();
}
if (oldBrush != null)
Layer.Properties.Brush = oldBrush;
// Update the KeyboardPropertiesViewModel if it's being used
var model = LayerPropertiesViewModel as KeyboardPropertiesViewModel;
if (model != null)

View File

@ -17,6 +17,7 @@ using Artemis.Styles.DropTargetAdorners;
using Artemis.Utilities;
using Caliburn.Micro;
using GongSolutions.Wpf.DragDrop;
using MahApps.Metro.Controls.Dialogs;
using Ninject;
using DragDropEffects = System.Windows.DragDropEffects;
using IDropTarget = GongSolutions.Wpf.DragDrop.IDropTarget;
@ -191,6 +192,12 @@ namespace Artemis.ViewModels.Profiles
if (e.PropertyName == "KeyboardPreview")
return;
if (e.PropertyName == "SelectedLayer")
{
NotifyOfPropertyChange(() => LayerSelected);
return;
}
if (SelectedProfile != null)
ProfileProvider.AddOrUpdate(SelectedProfile);
@ -203,9 +210,8 @@ namespace Artemis.ViewModels.Profiles
Layers.Clear();
if (SelectedProfile != null)
Layers.AddRange(SelectedProfile.Layers);
// Update booleans
NotifyOfPropertyChange(() => ProfileSelected);
NotifyOfPropertyChange(() => LayerSelected);
}
/// <summary>
@ -226,14 +232,14 @@ namespace Artemis.ViewModels.Profiles
if (ProfileViewModel.SelectedLayer == null)
return;
LayerEditor(ProfileViewModel.SelectedLayer);
EditLayer(ProfileViewModel.SelectedLayer);
}
/// <summary>
/// Opens a new LayerEditorView for the given layer
/// </summary>
/// <param name="layer">The layer to open the view for</param>
public void LayerEditor(LayerModel layer)
public void EditLayer(LayerModel layer)
{
IWindowManager manager = new WindowManager();
_editorVm = new LayerEditorViewModel(_gameModel.GameDataModel, layer);
@ -273,10 +279,27 @@ namespace Artemis.ViewModels.Profiles
if (SelectedProfile == null)
return;
var layer = SelectedProfile.AddLayer();
Layers.Add(layer);
// Create a new layer
var layer = LayerModel.CreateLayer();
ProfileViewModel.SelectedLayer = layer;
// If there is a selected layer and it has a parent, bind the new layer to it
if (ProfileViewModel.SelectedLayer?.Parent != null)
{
layer.Order = ProfileViewModel.SelectedLayer.Order + 1;
ProfileViewModel.SelectedLayer.Parent.Children.Add(layer);
ProfileViewModel.SelectedLayer.Parent.FixOrder();
}
else
{
// If there was no parent but there is a layer selected, put it below the selected layer
if (ProfileViewModel.SelectedLayer != null)
layer.Order = ProfileViewModel.SelectedLayer.Order + 1;
SelectedProfile.Layers.Add(layer);
SelectedProfile.FixOrder();
}
UpdateLayerList(layer);
}
/// <summary>
@ -284,27 +307,58 @@ namespace Artemis.ViewModels.Profiles
/// </summary>
public void RemoveLayer()
{
if (SelectedProfile == null || ProfileViewModel.SelectedLayer == null)
return;
SelectedProfile.Layers.Remove(ProfileViewModel.SelectedLayer);
Layers.Remove(ProfileViewModel.SelectedLayer);
SelectedProfile.FixOrder();
RemoveLayer(ProfileViewModel.SelectedLayer);
}
/// <summary>
/// Removes the given layer from the profile
/// </summary>
/// <param name="layer"></param>
public void RemoveLayerFromMenu(LayerModel layer)
public void RemoveLayer(LayerModel layer)
{
SelectedProfile.Layers.Remove(layer);
Layers.Remove(layer);
if (layer == null)
return;
SelectedProfile.FixOrder();
if (layer.Parent != null)
{
var parent = layer.Parent;
layer.Parent.Children.Remove(layer);
parent.FixOrder();
}
else if (layer.Profile != null)
{
var profile = layer.Profile;
layer.Profile.Layers.Remove(layer);
profile.FixOrder();
}
// Extra cleanup in case of a wonky layer that has no parent
if (SelectedProfile.Layers.Contains(layer))
SelectedProfile.Layers.Remove(layer);
UpdateLayerList(null);
}
public async void RenameLayer(LayerModel layer)
{
if (layer == null)
return;
var newName =
await
DialogService.ShowInputDialog("Rename layer", "Please enter a name for the layer",
new MetroDialogSettings {DefaultText = layer.Name});
// Null when the user cancelled
if (string.IsNullOrEmpty(newName))
return;
layer.Name = newName;
UpdateLayerList(layer);
}
/// <summary>
/// Clones the currently selected layer and adds it to the profile, on top of the original
/// </summary>
public void CloneLayer()
{
if (ProfileViewModel.SelectedLayer == null)
@ -320,11 +374,20 @@ namespace Artemis.ViewModels.Profiles
public void CloneLayer(LayerModel layer)
{
var clone = GeneralHelpers.Clone(layer);
clone.Order = layer.Order - 1;
SelectedProfile.Layers.Add(clone);
Layers.Add(clone);
clone.Order++;
SelectedProfile.FixOrder();
if (layer.Parent != null)
{
layer.Parent.Children.Add(clone);
layer.Parent.FixOrder();
}
else if (layer.Profile != null)
{
layer.Profile.Layers.Add(clone);
layer.Profile.FixOrder();
}
UpdateLayerList(clone);
}
private void UpdateLayerList(LayerModel selectModel)
@ -334,6 +397,9 @@ namespace Artemis.ViewModels.Profiles
if (SelectedProfile != null)
Layers.AddRange(SelectedProfile.Layers);
if (selectModel == null)
return;
// A small delay to allow the profile list to rebuild
Task.Factory.StartNew(() =>
{

View File

@ -158,10 +158,10 @@
<StackPanel.ContextMenu>
<ContextMenu
cal:Action.TargetWithoutContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Rename" />
<MenuItem Header="Rename" cal:Message.Attach="RenameLayer($datacontext)" />
<MenuItem Header="Duplicate" cal:Message.Attach="CloneLayer($datacontext)" />
<MenuItem Header="Delete" cal:Message.Attach="RemoveLayerFromMenu($datacontext)" />
<MenuItem Header="Properties" cal:Message.Attach="LayerEditor($datacontext)" />
<MenuItem Header="Delete" cal:Message.Attach="RemoveLayer($datacontext)" />
<MenuItem Header="Properties" cal:Message.Attach="EditLayer($datacontext)" />
</ContextMenu>
</StackPanel.ContextMenu>
<CheckBox VerticalAlignment="Center" ToolTip="Layer enabled" IsChecked="{Binding Enabled}" />
@ -192,7 +192,7 @@
</Button.Content>
</Button>
<Button x:Name="EditLayer" VerticalAlignment="Top" Style="{DynamicResource SquareButtonStyle}"
Width="26" Height="26" HorizontalAlignment="Right" Margin="10,0,0,0" ToolTip="Rename layer"
Width="26" Height="26" HorizontalAlignment="Right" Margin="10,0,0,0" ToolTip="Edit layer"
IsEnabled="{Binding Path=LayerSelected}">
<Button.Content>
<Rectangle