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

Added profile import, profile editor UI polish

This commit is contained in:
SpoinkyNL 2016-05-26 21:03:15 +02:00
parent a596382274
commit 5a19bf9e30
15 changed files with 335 additions and 102 deletions

View File

@ -196,7 +196,7 @@
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL"> <Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
<HintPath>..\packages\NLog.4.3.3\lib\net45\NLog.dll</HintPath> <HintPath>..\packages\NLog.4.3.4\lib\net45\NLog.dll</HintPath>
<Private>True</Private> <Private>True</Private>
</Reference> </Reference>
<Reference Include="SharpDX, Version=3.0.2.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL"> <Reference Include="SharpDX, Version=3.0.2.0, Culture=neutral, PublicKeyToken=b4dcf0f35e5521f1, processorArchitecture=MSIL">
@ -283,7 +283,7 @@
<Compile Include="ArtemisBootstrapper.cs" /> <Compile Include="ArtemisBootstrapper.cs" />
<Compile Include="DAL\ProfileProvider.cs" /> <Compile Include="DAL\ProfileProvider.cs" />
<Compile Include="DeviceProviders\Corsair\CorsairMice.cs" /> <Compile Include="DeviceProviders\Corsair\CorsairMice.cs" />
<Compile Include="DeviceProviders\Corsair\CorsiarHeadsets.cs" /> <Compile Include="DeviceProviders\Corsair\CorsairHeadsets.cs" />
<Compile Include="DeviceProviders\DeviceProvider.cs" /> <Compile Include="DeviceProviders\DeviceProvider.cs" />
<Compile Include="Events\ActiveKeyboardChanged.cs" /> <Compile Include="Events\ActiveKeyboardChanged.cs" />
<Compile Include="Events\ToggleEnabled.cs" /> <Compile Include="Events\ToggleEnabled.cs" />

View File

@ -96,5 +96,24 @@ namespace Artemis.DAL
Directory.CreateDirectory(ProfileFolder); Directory.CreateDirectory(ProfileFolder);
Debug.WriteLine("Place presets"); Debug.WriteLine("Place presets");
} }
public static ProfileModel LoadProfileIfValid(string path)
{
try
{
var deserializer = new XmlSerializer(typeof(ProfileModel));
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))
return null;
return prof;
}
}
catch (InvalidOperationException)
{
return null;
}
}
} }
} }

View File

@ -33,7 +33,7 @@ namespace Artemis.DeviceProviders.Corsair
public override void Disable() public override void Disable()
{ {
if (CueSDK.ProtocolDetails != null) if (CueSDK.ProtocolDetails != null)
CueSDK.Reinitialize(); CueSDK.Reinitialize(true);
} }
public override void UpdateDevice(Brush brush) public override void UpdateDevice(Brush brush)
@ -72,7 +72,7 @@ namespace Artemis.DeviceProviders.Corsair
try try
{ {
if (CueSDK.ProtocolDetails == null) if (CueSDK.ProtocolDetails == null)
CueSDK.Initialize(); CueSDK.Initialize(true);
else else
return true; return true;
} }
@ -87,7 +87,7 @@ namespace Artemis.DeviceProviders.Corsair
} }
catch (WrapperException) catch (WrapperException)
{ {
CueSDK.Reinitialize(); CueSDK.Reinitialize(true);
return true; return true;
} }

View File

@ -33,7 +33,7 @@ namespace Artemis.DeviceProviders.Corsair
public override void Disable() public override void Disable()
{ {
if (CueSDK.ProtocolDetails != null) if (CueSDK.ProtocolDetails != null)
CueSDK.Reinitialize(); CueSDK.Reinitialize(true);
} }
public override void UpdateDevice(Brush brush) public override void UpdateDevice(Brush brush)
@ -73,7 +73,7 @@ namespace Artemis.DeviceProviders.Corsair
try try
{ {
if (CueSDK.ProtocolDetails == null) if (CueSDK.ProtocolDetails == null)
CueSDK.Initialize(); CueSDK.Initialize(true);
else else
return true; return true;
} }
@ -88,7 +88,7 @@ namespace Artemis.DeviceProviders.Corsair
} }
catch (WrapperException) catch (WrapperException)
{ {
CueSDK.Reinitialize(); CueSDK.Reinitialize(true);
return true; return true;
} }

View File

@ -33,7 +33,7 @@ namespace Artemis.DeviceProviders.Corsair
try try
{ {
if (CueSDK.ProtocolDetails == null) if (CueSDK.ProtocolDetails == null)
CueSDK.Initialize(); CueSDK.Initialize(true);
} }
catch (CUEException e) catch (CUEException e)
{ {
@ -46,7 +46,7 @@ namespace Artemis.DeviceProviders.Corsair
} }
catch (WrapperException) catch (WrapperException)
{ {
CueSDK.Reinitialize(); CueSDK.Reinitialize(true);
return true; return true;
} }
@ -93,7 +93,7 @@ namespace Artemis.DeviceProviders.Corsair
public override void Disable() public override void Disable()
{ {
if (CueSDK.ProtocolDetails != null) if (CueSDK.ProtocolDetails != null)
CueSDK.Reinitialize(); CueSDK.Reinitialize(true);
} }
/// <summary> /// <summary>

View File

@ -23,9 +23,13 @@ namespace Artemis.Models.Profiles
// Put the subject in a list, allowing Dynamic Linq to be used. // Put the subject in a list, allowing Dynamic Linq to be used.
var subjectList = new List<T> {(T) subject}; var subjectList = new List<T> {(T) subject};
var res = Type == "String" bool res;
? subjectList.Where($"{Field}.ToLower() {Operator} @0", Value.ToLower()).Any() if (Type == "String")
: subjectList.Where($"{Field} {Operator} {Value}").Any(); res = subjectList.Where($"{Field}.ToLower() {Operator} @0", Value.ToLower()).Any();
else if (Type == "Enum")
res = subjectList.Where($"{Field} {Operator} \"{Value}\"").Any();
else
res = subjectList.Where($"{Field} {Operator} {Value}").Any();
return res; return res;
} }
} }

View File

@ -166,12 +166,12 @@ namespace Artemis.Models.Profiles
return Enabled && (LayerType == LayerType.Keyboard || LayerType == LayerType.KeyboardGif); return Enabled && (LayerType == LayerType.Keyboard || LayerType == LayerType.KeyboardGif);
} }
public IEnumerable<LayerModel> GetAllLayers() public IEnumerable<LayerModel> GetAllLayers(bool ignoreEnabled)
{ {
var layers = new List<LayerModel>(); var layers = new List<LayerModel>();
foreach (var layerModel in Children) foreach (var layerModel in Children)
{ {
if (!layerModel.Enabled) if (ignoreEnabled && !layerModel.Enabled)
continue; continue;
layers.Add(layerModel); layers.Add(layerModel);
layers.AddRange(layerModel.Children); layers.AddRange(layerModel.Children);

View File

@ -1,5 +1,4 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Linq; using System.Linq;
using System.Windows; using System.Windows;
@ -11,6 +10,8 @@ using Artemis.Utilities;
using Artemis.Utilities.ParentChild; using Artemis.Utilities.ParentChild;
using Brush = System.Windows.Media.Brush; using Brush = System.Windows.Media.Brush;
using Color = System.Windows.Media.Color; using Color = System.Windows.Media.Color;
using Point = System.Windows.Point;
using Size = System.Windows.Size;
namespace Artemis.Models.Profiles namespace Artemis.Models.Profiles
{ {
@ -137,18 +138,38 @@ namespace Artemis.Models.Profiles
/// <summary> /// <summary>
/// Gives all the layers and their children in a flat list /// Gives all the layers and their children in a flat list
/// </summary> /// </summary>
public List<LayerModel> GetEnabledLayers() public List<LayerModel> GetLayers(bool ignoreEnabled = true)
{ {
var layers = new List<LayerModel>(); var layers = new List<LayerModel>();
foreach (var layerModel in Layers) foreach (var layerModel in Layers)
{ {
if (!layerModel.Enabled) if (ignoreEnabled && !layerModel.Enabled)
{
continue; continue;
}
layers.Add(layerModel); layers.Add(layerModel);
layers.AddRange(layerModel.GetAllLayers()); layers.AddRange(layerModel.GetAllLayers(ignoreEnabled));
} }
return layers; return layers;
} }
public void FixBoundaries(Rect keyboardRectangle)
{
foreach (var layer in GetLayers(false))
{
if (layer.LayerType != LayerType.Keyboard && layer.LayerType != LayerType.KeyboardGif)
continue;
var props = (KeyboardPropertiesModel) layer.Properties;
var layerRect = new Rect(new Point(props.X, props.Y), new Size(props.Width, props.Height));
if (keyboardRectangle.Contains(layerRect))
continue;
props.X = 0;
props.Y = 0;
layer.Properties = props;
}
}
} }
} }

View File

@ -15,16 +15,17 @@
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="80" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,1,0">
<Label FontSize="20" HorizontalAlignment="Left"> <Label FontSize="20" HorizontalAlignment="Left">
<Label.Content> <Label.Content>
<AccessText TextWrapping="Wrap" <AccessText TextWrapping="Wrap"
Text="Shows lots of things, I should change this." /> Text="Shows verious game states and events on the keyboard." />
</Label.Content> </Label.Content>
</Label> </Label>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
@ -36,10 +37,11 @@
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
<TextBlock Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Center" Margin="0,8" <TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,1,0" VerticalAlignment="Center"
TextWrapping="Wrap" HorizontalAlignment="Left" FontFamily="Segoe UI Semibold" TextWrapping="Wrap" HorizontalAlignment="Left" FontFamily="Segoe UI Semibold"
Foreground="{DynamicResource HighlightBrush}" MaxWidth="510" TextAlignment="Justify"> Foreground="{DynamicResource HighlightBrush}" MaxWidth="510" TextAlignment="Justify">
Note: For this game to work with Artemis, please open up your Division settings, navigate to 3rd Party and set LED keyboard support to Yes. (This only works if you have Artemis running before starting the game) Note: For this game to work with Artemis, please open up your Division settings, navigate to 3rd Party
and set LED keyboard support to Yes. (This only works if you have Artemis running before starting the game)
</TextBlock> </TextBlock>
<!-- Profile editor --> <!-- Profile editor -->

View File

@ -16,8 +16,8 @@
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="*" />
<RowDefinition />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2"> <StackPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
<Label FontSize="20" HorizontalAlignment="Left"> <Label FontSize="20" HorizontalAlignment="Left">
@ -35,18 +35,13 @@
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
<TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Center" Margin="0,8" <TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Center" Margin="0,8"
TextWrapping="Wrap" HorizontalAlignment="Left" FontFamily="Segoe UI Semibold" TextWrapping="Wrap" HorizontalAlignment="Left" FontFamily="Segoe UI Semibold" TextAlignment="Justify" MaxWidth="820">
MaxWidth="510" TextAlignment="Justify">
Artemis requires the latest Witcher 3 version and mod to be installed in order to work. If you don't use any (conflicting) Witcher 3 mods, the mod can automatically be installed. Artemis requires the latest Witcher 3 version and mod to be installed in order to work. If you don't use any (conflicting) Witcher 3 mods, the mod can automatically be installed.
</TextBlock> </TextBlock>
<Button Grid.Row="2" Grid.Column="0" x:Name="AutoInstall" Content="Try automatic mod install" Width="160" Style="{DynamicResource SquareButtonStyle}" HorizontalAlignment="Left" />
<TextBlock Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" VerticalAlignment="Center" Margin="0,8" <!-- Profile editor -->
TextWrapping="Wrap" HorizontalAlignment="Left" FontFamily="Segoe UI Semibold" <ContentControl Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" x:Name="ProfileEditor" Margin="0,0,-30,0" />
Foreground="{DynamicResource HighlightBrush}" MaxWidth="510" TextAlignment="Justify">
Note: If you do use conflicting mods, we'll let you know what to do.
</TextBlock>
<Button Grid.Row="3" Grid.Column="0" x:Name="AutoInstall" Content="Try automatic mod install" Width="160"
Style="{DynamicResource SquareButtonStyle}" HorizontalAlignment="Left" Margin="0,20,0,0" />
<!-- Buttons --> <!-- Buttons -->
<StackPanel Grid.Column="0" Grid.Row="4" Orientation="Horizontal" VerticalAlignment="Bottom"> <StackPanel Grid.Column="0" Grid.Row="4" Orientation="Horizontal" VerticalAlignment="Bottom">

View File

@ -6,7 +6,7 @@ using Caliburn.Micro;
namespace Artemis.ViewModels.LayerEditor namespace Artemis.ViewModels.LayerEditor
{ {
public class LayerConditionViewModel : Screen public sealed class LayerConditionViewModel : Screen
{ {
private readonly NamedOperator[] _boolOperators = private readonly NamedOperator[] _boolOperators =
{ {
@ -32,9 +32,10 @@ namespace Artemis.ViewModels.LayerEditor
new NamedOperator("Not equal to", "!=") new NamedOperator("Not equal to", "!=")
}; };
private bool _enumValueIsVisible;
private bool _preselecting; private bool _preselecting;
private GeneralHelpers.PropertyCollection _selectedDataModelProp; private GeneralHelpers.PropertyCollection _selectedDataModelProp;
private string _selectedEnum;
private NamedOperator _selectedOperator; private NamedOperator _selectedOperator;
private string _userValue; private string _userValue;
private bool _userValueIsVisible; private bool _userValueIsVisible;
@ -48,6 +49,7 @@ namespace Artemis.ViewModels.LayerEditor
LayerConditionModel = layerConditionModel; LayerConditionModel = layerConditionModel;
DataModelProps = dataModelProps; DataModelProps = dataModelProps;
Operators = new BindableCollection<NamedOperator>(); Operators = new BindableCollection<NamedOperator>();
Enums = new BindableCollection<string>();
PropertyChanged += UpdateModel; PropertyChanged += UpdateModel;
PropertyChanged += UpdateForm; PropertyChanged += UpdateForm;
@ -55,6 +57,13 @@ namespace Artemis.ViewModels.LayerEditor
PreSelect(); PreSelect();
} }
public LayerConditionModel LayerConditionModel { get; set; }
public BindableCollection<GeneralHelpers.PropertyCollection> DataModelProps { get; set; }
public BindableCollection<NamedOperator> Operators { get; set; }
public BindableCollection<string> Enums { get; set; }
public string UserValue public string UserValue
{ {
get { return _userValue; } get { return _userValue; }
@ -66,10 +75,6 @@ namespace Artemis.ViewModels.LayerEditor
} }
} }
public LayerConditionModel LayerConditionModel { get; set; }
public BindableCollection<GeneralHelpers.PropertyCollection> DataModelProps { get; set; }
public BindableCollection<NamedOperator> Operators { get; set; }
public GeneralHelpers.PropertyCollection SelectedDataModelProp public GeneralHelpers.PropertyCollection SelectedDataModelProp
{ {
get { return _selectedDataModelProp; } get { return _selectedDataModelProp; }
@ -93,6 +98,17 @@ namespace Artemis.ViewModels.LayerEditor
} }
} }
public bool EnumValueIsVisible
{
get { return _enumValueIsVisible; }
set
{
if (value == _enumValueIsVisible) return;
_enumValueIsVisible = value;
NotifyOfPropertyChange(() => EnumValueIsVisible);
}
}
public NamedOperator SelectedOperator public NamedOperator SelectedOperator
{ {
get { return _selectedOperator; } get { return _selectedOperator; }
@ -104,6 +120,17 @@ namespace Artemis.ViewModels.LayerEditor
} }
} }
public string SelectedEnum
{
get { return _selectedEnum; }
set
{
if (value == _selectedEnum) return;
_selectedEnum = value;
NotifyOfPropertyChange(() => SelectedEnum);
}
}
/// <summary> /// <summary>
/// Handles updating the form to match the selected data model property /// Handles updating the form to match the selected data model property
/// </summary> /// </summary>
@ -115,32 +142,35 @@ namespace Artemis.ViewModels.LayerEditor
return; return;
Operators.Clear(); Operators.Clear();
UserValueIsVisible = false;
EnumValueIsVisible = false;
switch (SelectedDataModelProp.Type)
{
case "Int32":
Operators.AddRange(_int32Operators);
UserValueIsVisible = true;
break;
case "Boolean":
Operators.AddRange(_boolOperators);
break;
default:
Operators.AddRange(_operators);
UserValueIsVisible = true;
break;
}
// Setup Enum selection if needed
if (SelectedDataModelProp.EnumValues != null) if (SelectedDataModelProp.EnumValues != null)
{ {
Operators.AddRange( Enums.AddRange(SelectedDataModelProp.EnumValues);
SelectedDataModelProp.EnumValues.Select(val => new NamedOperator(val.SplitCamelCase(), "== " + val))); EnumValueIsVisible = true;
UserValueIsVisible = false;
} }
else
switch (SelectedDataModelProp.Type)
{
case "Int32":
Operators.AddRange(_int32Operators);
UserValueIsVisible = true;
break;
case "Boolean":
Operators.AddRange(_boolOperators);
UserValueIsVisible = false;
break;
default:
Operators.AddRange(_operators);
UserValueIsVisible = true;
break;
}
SelectedOperator = Operators.First(); SelectedOperator = Operators.First();
} }
/// <summary> /// <summary>
/// Handles saving user input to the model /// Handles saving user input to the model
/// TODO: Data validation? /// TODO: Data validation?
@ -156,13 +186,14 @@ namespace Artemis.ViewModels.LayerEditor
// Only care about these fields // Only care about these fields
if (e.PropertyName != "UserValue" && if (e.PropertyName != "UserValue" &&
e.PropertyName != "SelectedOperator" && e.PropertyName != "SelectedOperator" &&
e.PropertyName != "SelectedDataModelProp") e.PropertyName != "SelectedDataModelProp" &&
e.PropertyName != "SelectedEnum")
return; return;
LayerConditionModel.Field = SelectedDataModelProp.Path; LayerConditionModel.Field = SelectedDataModelProp.Path;
LayerConditionModel.Operator = SelectedOperator.Value; LayerConditionModel.Operator = SelectedOperator.Value;
LayerConditionModel.Value = UserValue;
LayerConditionModel.Type = SelectedDataModelProp.Type; LayerConditionModel.Type = SelectedDataModelProp.Type;
LayerConditionModel.Value = SelectedDataModelProp.Type == "Enum" ? SelectedEnum : UserValue;
} }
/// <summary> /// <summary>
@ -173,8 +204,12 @@ namespace Artemis.ViewModels.LayerEditor
_preselecting = true; _preselecting = true;
SelectedDataModelProp = DataModelProps.FirstOrDefault(m => m.Path == LayerConditionModel.Field); SelectedDataModelProp = DataModelProps.FirstOrDefault(m => m.Path == LayerConditionModel.Field);
SelectedOperator = Operators.FirstOrDefault(o => o.Value == LayerConditionModel.Operator); SelectedOperator = Operators.FirstOrDefault(o => o.Value == LayerConditionModel.Operator);
UserValue = LayerConditionModel.Value;
LayerConditionModel.Type = SelectedDataModelProp.Type; LayerConditionModel.Type = SelectedDataModelProp.Type;
if (LayerConditionModel.Type =="Enum")
SelectedEnum = LayerConditionModel.Value;
else
UserValue = LayerConditionModel.Value;
_preselecting = false; _preselecting = false;
} }

View File

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using System.Timers; using System.Timers;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Forms;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Threading; using System.Windows.Threading;
@ -25,6 +26,13 @@ using Caliburn.Micro;
using GongSolutions.Wpf.DragDrop; using GongSolutions.Wpf.DragDrop;
using MahApps.Metro; using MahApps.Metro;
using Ninject; using Ninject;
using Application = System.Windows.Application;
using Cursor = System.Windows.Input.Cursor;
using Cursors = System.Windows.Input.Cursors;
using DragDropEffects = System.Windows.DragDropEffects;
using IDropTarget = GongSolutions.Wpf.DragDrop.IDropTarget;
using MouseEventArgs = System.Windows.Input.MouseEventArgs;
using Screen = Caliburn.Micro.Screen;
using Timer = System.Timers.Timer; using Timer = System.Timers.Timer;
namespace Artemis.ViewModels namespace Artemis.ViewModels
@ -45,7 +53,8 @@ namespace Artemis.ViewModels
private LayerModel _selectedLayer; private LayerModel _selectedLayer;
private ProfileModel _selectedProfile; private ProfileModel _selectedProfile;
public ProfileEditorViewModel(IEventAggregator events, MainManager mainManager, GameModel gameModel) public ProfileEditorViewModel(IEventAggregator events, MainManager mainManager, GameModel gameModel,
MetroDialogService dialogService)
{ {
_mainManager = mainManager; _mainManager = mainManager;
_gameModel = gameModel; _gameModel = gameModel;
@ -53,13 +62,13 @@ namespace Artemis.ViewModels
Profiles = new BindableCollection<ProfileModel>(); Profiles = new BindableCollection<ProfileModel>();
Layers = new BindableCollection<LayerModel>(); Layers = new BindableCollection<LayerModel>();
ActiveKeyboard = _mainManager.DeviceManager.ActiveKeyboard; ActiveKeyboard = _mainManager.DeviceManager.ActiveKeyboard;
DialogService = dialogService;
events.Subscribe(this); events.Subscribe(this);
PreviewTimer = new Timer(40); PreviewTimer = new Timer(40);
PreviewTimer.Elapsed += InvokeUpdateKeyboardPreview; PreviewTimer.Elapsed += InvokeUpdateKeyboardPreview;
PropertyChanged += PropertyChangeHandler; PropertyChanged += PropertyChangeHandler;
LoadProfiles(); LoadProfiles();
} }
@ -99,7 +108,7 @@ namespace Artemis.ViewModels
if (Equals(value, _selectedLayer)) return; if (Equals(value, _selectedLayer)) return;
_selectedLayer = value; _selectedLayer = value;
NotifyOfPropertyChange(() => SelectedLayer); NotifyOfPropertyChange(() => SelectedLayer);
NotifyOfPropertyChange(() => CanRemoveLayer); NotifyOfPropertyChange(() => LayerSelected);
} }
} }
@ -127,8 +136,8 @@ namespace Artemis.ViewModels
Layers.AddRange(SelectedProfile.Layers); Layers.AddRange(SelectedProfile.Layers);
NotifyOfPropertyChange(() => SelectedProfile); NotifyOfPropertyChange(() => SelectedProfile);
NotifyOfPropertyChange(() => CanAddLayer); NotifyOfPropertyChange(() => ProfileSelected);
NotifyOfPropertyChange(() => CanRemoveLayer); NotifyOfPropertyChange(() => LayerSelected);
} }
} }
@ -147,8 +156,8 @@ namespace Artemis.ViewModels
public PreviewSettings? PreviewSettings => ActiveKeyboard?.PreviewSettings; public PreviewSettings? PreviewSettings => ActiveKeyboard?.PreviewSettings;
public bool CanAddLayer => SelectedProfile != null; public bool ProfileSelected => SelectedProfile != null;
public bool CanRemoveLayer => SelectedProfile != null && _selectedLayer != null; public bool LayerSelected => SelectedProfile != null && _selectedLayer != null;
private KeyboardProvider ActiveKeyboard { get; set; } private KeyboardProvider ActiveKeyboard { get; set; }
@ -293,6 +302,14 @@ namespace Artemis.ViewModels
SelectedProfile = profile; SelectedProfile = profile;
} }
public void EditLayer()
{
if (SelectedLayer == null)
return;
LayerEditor(SelectedLayer);
}
/// <summary> /// <summary>
/// Opens a new LayerEditorView for the given layer /// Opens a new LayerEditorView for the given layer
/// </summary> /// </summary>
@ -369,6 +386,14 @@ namespace Artemis.ViewModels
SelectedProfile.FixOrder(); SelectedProfile.FixOrder();
} }
public void CloneLayer()
{
if (SelectedLayer == null)
return;
CloneLayer(SelectedLayer);
}
/// <summary> /// <summary>
/// Clones the given layer and adds it to the profile, on top of the original /// Clones the given layer and adds it to the profile, on top of the original
/// </summary> /// </summary>
@ -426,7 +451,7 @@ namespace Artemis.ViewModels
var x = pos.X/((double) ActiveKeyboard.PreviewSettings.Width/ActiveKeyboard.Width); var x = pos.X/((double) ActiveKeyboard.PreviewSettings.Width/ActiveKeyboard.Width);
var y = pos.Y/((double) ActiveKeyboard.PreviewSettings.Height/ActiveKeyboard.Height); var y = pos.Y/((double) ActiveKeyboard.PreviewSettings.Height/ActiveKeyboard.Height);
var hoverLayer = SelectedProfile.GetEnabledLayers() var hoverLayer = SelectedProfile.GetLayers()
.Where(l => l.MustDraw()) .Where(l => l.MustDraw())
.FirstOrDefault(l => ((KeyboardPropertiesModel) l.Properties) .FirstOrDefault(l => ((KeyboardPropertiesModel) l.Properties)
.GetRect(1) .GetRect(1)
@ -447,7 +472,7 @@ namespace Artemis.ViewModels
var pos = e.GetPosition((Image) e.OriginalSource); var pos = e.GetPosition((Image) e.OriginalSource);
var x = pos.X/((double) ActiveKeyboard.PreviewSettings.Width/ActiveKeyboard.Width); var x = pos.X/((double) ActiveKeyboard.PreviewSettings.Width/ActiveKeyboard.Width);
var y = pos.Y/((double) ActiveKeyboard.PreviewSettings.Height/ActiveKeyboard.Height); var y = pos.Y/((double) ActiveKeyboard.PreviewSettings.Height/ActiveKeyboard.Height);
var hoverLayer = SelectedProfile.GetEnabledLayers() var hoverLayer = SelectedProfile.GetLayers()
.Where(l => l.MustDraw()) .Where(l => l.MustDraw())
.FirstOrDefault(l => ((KeyboardPropertiesModel) l.Properties) .FirstOrDefault(l => ((KeyboardPropertiesModel) l.Properties)
.GetRect(1).Contains(x, y)); .GetRect(1).Contains(x, y));
@ -594,5 +619,59 @@ namespace Artemis.ViewModels
draggingProps.Y = (int) Math.Round(y - _draggingLayerOffset.Value.Y); draggingProps.Y = (int) Math.Round(y - _draggingLayerOffset.Value.Y);
} }
} }
public async void ImportProfile()
{
var dialog = new OpenFileDialog {Filter = "Artemis profile (*.xml)|*.xml"};
var result = dialog.ShowDialog();
if (result != DialogResult.OK)
return;
var profile = ProfileProvider.LoadProfileIfValid(dialog.FileName);
if (profile == null)
{
DialogService.ShowErrorMessageBox("Oh noes, the profile you provided is invalid. " +
"If this keeps happening, please make an issue on GitHub and provide the profile.");
return;
}
// Verify the game
if (profile.GameName != _gameModel.Name)
{
DialogService.ShowErrorMessageBox(
$"Oh oops! This profile is ment for {profile.GameName}, not {_gameModel.Name} :c");
return;
}
// Verify the keyboard
if (profile.KeyboardName != _mainManager.DeviceManager.ActiveKeyboard.Name)
{
var adjustKeyboard = await DialogService.ShowQuestionMessageBox("Profile not inteded for this keyboard",
$"Watch out, this profile wasn't ment for this keyboard, but for the {profile.KeyboardName}. " +
"You can still import it but you'll probably have to do some adjusting\n\n" +
"Continue?");
if (!adjustKeyboard.Value)
return;
profile.KeyboardName = _mainManager.DeviceManager.ActiveKeyboard.Name;
profile.FixBoundaries(_mainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(1));
}
// Verify the name
while (ProfileProvider.GetAll().Contains(profile))
{
profile.Name = await DialogService.ShowInputDialog("Rename imported profile",
"A profile with this name already exists for this game. Please enter a new name");
// Null when the user cancelled
if (string.IsNullOrEmpty(profile.Name))
return;
}
ProfileProvider.AddOrUpdate(profile);
LoadProfiles();
SelectedProfile = Profiles.FirstOrDefault(p => p.Name == profile.Name);
}
} }
} }

View File

@ -54,6 +54,10 @@
<StackPanel Grid.Column="0" x:Name="UserValueIsVisible" HorizontalAlignment="Left" VerticalAlignment="Top"> <StackPanel Grid.Column="0" x:Name="UserValueIsVisible" HorizontalAlignment="Left" VerticalAlignment="Top">
<TextBox x:Name="UserValue" VerticalAlignment="Center" HorizontalAlignment="Left" Width="110" /> <TextBox x:Name="UserValue" VerticalAlignment="Center" HorizontalAlignment="Left" Width="110" />
</StackPanel> </StackPanel>
<StackPanel Grid.Column="0" x:Name="EnumValueIsVisible" HorizontalAlignment="Left" VerticalAlignment="Top">
<ComboBox x:Name="Enums" Width="110" MaxDropDownHeight="125" HorizontalAlignment="Center"
VerticalAlignment="Top"/>
</StackPanel>
<Button Grid.Column="1" x:Name="Delete" Width="26" Height="26" Style="{DynamicResource SquareButtonStyle}" <Button Grid.Column="1" x:Name="Delete" Width="26" Height="26" Style="{DynamicResource SquareButtonStyle}"
VerticalAlignment="Top" HorizontalAlignment="Right"> VerticalAlignment="Top" HorizontalAlignment="Right">
<Button.Content> <Button.Content>

View File

@ -7,9 +7,10 @@
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:itemBehaviours="clr-namespace:Artemis.ItemBehaviours" xmlns:itemBehaviours="clr-namespace:Artemis.ItemBehaviours"
xmlns:utilities="clr-namespace:Artemis.Utilities" xmlns:utilities="clr-namespace:Artemis.Utilities"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:dragDrop="clr-namespace:GongSolutions.Wpf.DragDrop;assembly=GongSolutions.Wpf.DragDrop" xmlns:dragDrop="clr-namespace:GongSolutions.Wpf.DragDrop;assembly=GongSolutions.Wpf.DragDrop"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="473" Width="1055"> d:DesignHeight="510" Width="1055">
<UserControl.Resources> <UserControl.Resources>
<utilities:LayerOrderConverter x:Key="LayerOrderConverter" /> <utilities:LayerOrderConverter x:Key="LayerOrderConverter" />
</UserControl.Resources> </UserControl.Resources>
@ -64,18 +65,6 @@
</Rectangle> </Rectangle>
</Button.Content> </Button.Content>
</Button> </Button>
<Button x:Name="DuplicateProfile" VerticalAlignment="Top" Style="{DynamicResource SquareButtonStyle}"
Width="26" Height="26" HorizontalAlignment="Right" Margin="10,0,0,0" ToolTip="Duplicate profile">
<Button.Content>
<Rectangle
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"
Width="12" Height="12">
<Rectangle.OpacityMask>
<VisualBrush Visual="{StaticResource appbar_clipboard_paste}" Stretch="Fill" />
</Rectangle.OpacityMask>
</Rectangle>
</Button.Content>
</Button>
<Button x:Name="EditProfile" VerticalAlignment="Top" Style="{DynamicResource SquareButtonStyle}" <Button x:Name="EditProfile" VerticalAlignment="Top" Style="{DynamicResource SquareButtonStyle}"
Width="26" Height="26" HorizontalAlignment="Right" Margin="10,0,0,0" ToolTip="Rename profile"> Width="26" Height="26" HorizontalAlignment="Right" Margin="10,0,0,0" ToolTip="Rename profile">
<Button.Content> <Button.Content>
@ -88,6 +77,18 @@
</Rectangle> </Rectangle>
</Button.Content> </Button.Content>
</Button> </Button>
<Button x:Name="DuplicateProfile" VerticalAlignment="Top" Style="{DynamicResource SquareButtonStyle}"
Width="26" Height="26" HorizontalAlignment="Right" Margin="10,0,0,0" ToolTip="Duplicate profile">
<Button.Content>
<Rectangle
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"
Width="12" Height="12">
<Rectangle.OpacityMask>
<VisualBrush Visual="{StaticResource appbar_clipboard_paste}" Stretch="Fill" />
</Rectangle.OpacityMask>
</Rectangle>
</Button.Content>
</Button>
<Button x:Name="RemoveProfile" VerticalAlignment="Top" Style="{DynamicResource SquareButtonStyle}" <Button x:Name="RemoveProfile" VerticalAlignment="Top" Style="{DynamicResource SquareButtonStyle}"
Width="26" Height="26" HorizontalAlignment="Right" Margin="10,0,0,0" ToolTip="Delete profile"> Width="26" Height="26" HorizontalAlignment="Right" Margin="10,0,0,0" ToolTip="Delete profile">
<Button.Content> <Button.Content>
@ -101,6 +102,38 @@
</Button.Content> </Button.Content>
</Button> </Button>
</StackPanel> </StackPanel>
<StackPanel Grid.Column="0" Grid.Row="2" Orientation="Horizontal" Margin="0,5,0,0" HorizontalAlignment="Right">
<Button x:Name="ImportProfile" VerticalAlignment="Top" Style="{DynamicResource SquareButtonStyle}"
Height="26" HorizontalAlignment="Right" ToolTip="Import profile">
<Button.Content>
<StackPanel Orientation="Horizontal">
<Rectangle
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"
Width="12" Height="12" Margin="3,0">
<Rectangle.OpacityMask>
<VisualBrush Visual="{StaticResource appbar_cabinet_in}" Stretch="Fill" />
</Rectangle.OpacityMask>
</Rectangle>
<TextBlock Margin="2,0,2,0">import profile</TextBlock>
</StackPanel>
</Button.Content>
</Button>
<Button x:Name="ExportProfile" VerticalAlignment="Top" Style="{DynamicResource SquareButtonStyle}"
Height="26" HorizontalAlignment="Right" Margin="10,0,0,0" IsEnabled="{Binding ProfileSelected}">
<Button.Content>
<StackPanel Orientation="Horizontal">
<Rectangle
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"
Width="12" Height="12" Margin="3,0">
<Rectangle.OpacityMask>
<VisualBrush Visual="{StaticResource appbar_cabinet_out}" Stretch="Fill" />
</Rectangle.OpacityMask>
</Rectangle>
<TextBlock Margin="2,0,2,0">export profile</TextBlock>
</StackPanel>
</Button.Content>
</Button>
</StackPanel>
<!-- Layer list --> <!-- Layer list -->
<Label Grid.Column="1" Grid.Row="0" FontSize="20" HorizontalAlignment="Left" Content="Layers" Margin="10,0,0,0" /> <Label Grid.Column="1" Grid.Row="0" FontSize="20" HorizontalAlignment="Left" Content="Layers" Margin="10,0,0,0" />
@ -144,18 +177,59 @@
</TreeView.ItemContainerStyle> </TreeView.ItemContainerStyle>
</TreeView> </TreeView>
</Border> </Border>
<Button Grid.Column="1" Grid.Row="2" Margin="10,5,0,0" x:Name="AddLayer" VerticalAlignment="Top" <StackPanel Grid.Column="1" Grid.Row="2" Orientation="Horizontal" Margin="10,5,0,0" HorizontalAlignment="Right">
Style="{DynamicResource SquareButtonStyle}" <Button x:Name="AddLayer" VerticalAlignment="Top"
Width="26" Height="26" ToolTip="Add layer" HorizontalAlignment="Right"> Style="{DynamicResource SquareButtonStyle}" IsEnabled="{Binding ProfileSelected}"
<Button.Content> Width="26" Height="26" ToolTip="Add layer" HorizontalAlignment="Left">
<Rectangle <Button.Content>
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}" <Rectangle
Width="12" Height="12"> Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"
<Rectangle.OpacityMask> Width="12" Height="12">
<VisualBrush Visual="{StaticResource appbar_add}" Stretch="Fill" /> <Rectangle.OpacityMask>
</Rectangle.OpacityMask> <VisualBrush Visual="{StaticResource appbar_add}" Stretch="Fill" />
</Rectangle> </Rectangle.OpacityMask>
</Button.Content> </Rectangle>
</Button> </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"
IsEnabled="{Binding Path=LayerSelected}">
<Button.Content>
<Rectangle
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"
Width="12" Height="12">
<Rectangle.OpacityMask>
<VisualBrush Visual="{StaticResource appbar_edit}" Stretch="Fill" />
</Rectangle.OpacityMask>
</Rectangle>
</Button.Content>
</Button>
<Button x:Name="CloneLayer" VerticalAlignment="Top" Style="{DynamicResource SquareButtonStyle}"
Width="26" Height="26" HorizontalAlignment="Right" Margin="10,0,0,0" ToolTip="Duplicate layer"
IsEnabled="{Binding Path=LayerSelected}">
<Button.Content>
<Rectangle
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"
Width="12" Height="12">
<Rectangle.OpacityMask>
<VisualBrush Visual="{StaticResource appbar_clipboard_paste}" Stretch="Fill" />
</Rectangle.OpacityMask>
</Rectangle>
</Button.Content>
</Button>
<Button x:Name="RemoveLayer" VerticalAlignment="Top" Style="{DynamicResource SquareButtonStyle}"
Width="26" Height="26" HorizontalAlignment="Right" Margin="10,0,0,0" ToolTip="Delete layer"
IsEnabled="{Binding Path=LayerSelected}">
<Button.Content>
<Rectangle
Fill="{Binding Path=Foreground, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Button}}}"
Width="12" Height="12">
<Rectangle.OpacityMask>
<VisualBrush Visual="{StaticResource appbar_delete}" Stretch="Fill" />
</Rectangle.OpacityMask>
</Rectangle>
</Button.Content>
</Button>
</StackPanel>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -18,8 +18,8 @@
<package id="Ninject.Extensions.Factory" version="3.2.1.0" targetFramework="net452" /> <package id="Ninject.Extensions.Factory" version="3.2.1.0" targetFramework="net452" />
<package id="Ninject.Extensions.Logging" version="3.2.3.0" targetFramework="net452" /> <package id="Ninject.Extensions.Logging" version="3.2.3.0" targetFramework="net452" />
<package id="Ninject.Extensions.Logging.nlog4" version="3.2.3.0" targetFramework="net452" /> <package id="Ninject.Extensions.Logging.nlog4" version="3.2.3.0" targetFramework="net452" />
<package id="NLog" version="4.3.3" targetFramework="net452" /> <package id="NLog" version="4.3.4" targetFramework="net452" />
<package id="NLog.Schema" version="4.3.0" targetFramework="net452" /> <package id="NLog.Schema" version="4.3.4" targetFramework="net452" />
<package id="SharpDX" version="3.0.2" targetFramework="net452" /> <package id="SharpDX" version="3.0.2" targetFramework="net452" />
<package id="SharpDX.Direct3D11" version="3.0.2" targetFramework="net452" /> <package id="SharpDX.Direct3D11" version="3.0.2" targetFramework="net452" />
<package id="SharpDX.DXGI" version="3.0.2" targetFramework="net452" /> <package id="SharpDX.DXGI" version="3.0.2" targetFramework="net452" />