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

Layer refactor (#118)

* Expanded Trace logging for Overwatch and RL, updated The Witcher 3 mod for 1.22

* Events WIP

* Moved some views around, added event views

* Implemented events

* Some improvements to Overwatch parsing.. some.

* Improved Overwatch parsing to work well with events

* Fixed ultimate ready false positive during ultimate usage

* Added debug window which currently shows Razer SDK keyboard output

* Expanded Overwatch data model (todo: sticky values to avoid false-positives)

* Added sticky values to Overwatch datamodel, should resolve most flickering/false positives

* Layer refactor WIP

* Moved layer types, animations, conditions and events to interfaces. (WIP)

* Code cleanup, moved all profile related models to their own folder/namespace

* Finished most of the profile refactoring

* More profile refactoring, app compiles again

* Switched from XML to JSON for profiles (refactor broke existing profiles anyway)

* Made animation event expiration generic and fixed all serialization issues I've come across so far

* Cleaned up settings, rigged basic LayerEditorView(Model) to refactored models

* Rigged most layer type viewmodels back up to the new models

* Fixed most view(models).
Added animations to mice and headset.
Replaced serialization-based cloning with NClone
Fixed some rendering issues that came up with refactoring

* Added Current Time to WindowsProfile

* Cloning fixes
Replaced glitchy cloning package with a simple serialization clone (that package looked so good :c)
Removed serialization cloning from render process

* Expanded Trace logging for Overwatch and RL, updated The Witcher 3 mod for 1.22

* Events WIP

* Moved some views around, added event views

* Implemented events

* Some improvements to Overwatch parsing.. some.

* Improved Overwatch parsing to work well with events

* Fixed ultimate ready false positive during ultimate usage

* Added debug window which currently shows Razer SDK keyboard output

* Expanded Overwatch data model (todo: sticky values to avoid false-positives)

* Added sticky values to Overwatch datamodel, should resolve most flickering/false positives

* Layer refactor WIP

* Moved layer types, animations, conditions and events to interfaces. (WIP)

* Code cleanup, moved all profile related models to their own folder/namespace

* Finished most of the profile refactoring

* More profile refactoring, app compiles again

* Switched from XML to JSON for profiles (refactor broke existing profiles anyway)

* Made animation event expiration generic and fixed all serialization issues I've come across so far

* Cleaned up settings, rigged basic LayerEditorView(Model) to refactored models

* Rigged most layer type viewmodels back up to the new models

* Fixed most view(models).
Added animations to mice and headset.
Replaced serialization-based cloning with NClone
Fixed some rendering issues that came up with refactoring

* Added Current Time to WindowsProfile

* Cloning fixes
Replaced glitchy cloning package with a simple serialization clone (that package looked so good :c)
Removed serialization cloning from render process
This commit is contained in:
Robert Beekman 2016-07-06 20:17:46 +02:00 committed by GitHub
parent 13122f8df7
commit 8d9272f47c
128 changed files with 3254 additions and 2364 deletions

View File

@ -52,38 +52,11 @@
<setting name="Enabled" serializeAs="String">
<value>True</value>
</setting>
<setting name="GameDirectory" serializeAs="String">
<value />
</setting>
<setting name="CanCastAbility" serializeAs="String">
<value>True</value>
</setting>
<setting name="ShowHealth" serializeAs="String">
<value>True</value>
</setting>
<setting name="ShowDayCycle" serializeAs="String">
<value>True</value>
</setting>
<setting name="ShowMana" serializeAs="String">
<value>True</value>
</setting>
<setting name="ShowEvents" serializeAs="String">
<value>True</value>
</setting>
<setting name="MainColor" serializeAs="String">
<value>#FFFF0000</value>
</setting>
<setting name="ManaColor" serializeAs="String">
<value>#FF0000FF</value>
</setting>
<setting name="KeyboardLayout" serializeAs="String">
<setting name="LastProfile" serializeAs="String">
<value>Default</value>
</setting>
<setting name="AbilityReadyColor" serializeAs="String">
<value>#FF00FF00</value>
</setting>
<setting name="AbilityCooldownColor" serializeAs="String">
<value>#FF6A5ACD</value>
<setting name="GameDirectory" serializeAs="String">
<value />
</setting>
</Artemis.Modules.Games.Dota2.Dota2>
<Artemis.Modules.Overlays.VolumeDisplay.VolumeDisplay>
@ -145,33 +118,12 @@
<setting name="Enabled" serializeAs="String">
<value>True</value>
</setting>
<setting name="GameDirectory" serializeAs="String">
<value />
</setting>
<setting name="AmmoEnabled" serializeAs="String">
<value>True</value>
</setting>
<setting name="AmmoMainColor" serializeAs="String">
<value>#FFFF2900</value>
</setting>
<setting name="AmmoSecondaryColor" serializeAs="String">
<value>#FF26F600</value>
</setting>
<setting name="TeamColorEnabled" serializeAs="String">
<value>True</value>
</setting>
<setting name="FlashEnabled" serializeAs="String">
<value>True</value>
</setting>
<setting name="SmokeEnabled" serializeAs="String">
<value>True</value>
</setting>
<setting name="LowHpEnabled" serializeAs="String">
<value>True</value>
</setting>
<setting name="LastProfile" serializeAs="String">
<value>Default</value>
</setting>
<setting name="GameDirectory" serializeAs="String">
<value />
</setting>
</Artemis.Modules.Games.CounterStrike.CounterStrike>
<Artemis.Settings.CounterStrike>
<setting name="GameDirectory" serializeAs="String">
@ -344,6 +296,10 @@
<assemblyIdentity name="Castle.Core" publicKeyToken="407dd0808d44fbdc" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-3.3.0.0" newVersion="3.3.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="NLog" publicKeyToken="5120e14c03d0593c" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.0.0" newVersion="4.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>

View File

@ -2,6 +2,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:artemis="clr-namespace:Artemis"
xmlns:converters="clr-namespace:Artemis.Utilities.Converters"
DispatcherUnhandledException="Application_DispatcherUnhandledException"
ShutdownMode="OnExplicitShutdown">
<Application.Resources>
@ -21,6 +22,7 @@
<ResourceDictionary Source="/Resources/Icons.xaml" />
<ResourceDictionary Source="Styles/ColorBox.xaml" />
</ResourceDictionary.MergedDictionaries>
<converters:MilliSecondTimespanConverter x:Key="MilliSecondTimespanConverter" />
</ResourceDictionary>
</Application.Resources>
</Application>

View File

@ -2,6 +2,7 @@
using System.Security.Principal;
using System.Windows;
using System.Windows.Threading;
using Artemis.Utilities;
using NLog;
using WpfExceptionViewer;
@ -14,8 +15,8 @@ namespace Artemis
{
public App()
{
//if (!IsRunAsAdministrator())
// GeneralHelpers.RunAsAdministrator();
if (!IsRunAsAdministrator())
GeneralHelpers.RunAsAdministrator();
InitializeComponent();
}

View File

@ -38,8 +38,8 @@
<SupportUrl>https://github.com/SpoinkyNL/Artemis/wiki/Frequently-Asked-Questions-%28FAQ%29</SupportUrl>
<ProductName>Artemis</ProductName>
<PublisherName>Artemis</PublisherName>
<ApplicationRevision>2</ApplicationRevision>
<ApplicationVersion>1.1.3.2</ApplicationVersion>
<ApplicationRevision>3</ApplicationRevision>
<ApplicationVersion>1.1.3.3</ApplicationVersion>
<UseApplicationTrust>false</UseApplicationTrust>
<CreateDesktopShortcut>true</CreateDesktopShortcut>
<PublishWizardCompleted>true</PublishWizardCompleted>
@ -276,9 +276,9 @@
<Compile Include="DeviceProviders\Corsair\CorsairHeadsets.cs" />
<Compile Include="DeviceProviders\DeviceProvider.cs" />
<Compile Include="Events\ActiveKeyboardChanged.cs" />
<Compile Include="Events\RazerColorArrayChanged.cs" />
<Compile Include="Events\ToggleEnabled.cs" />
<Compile Include="Events\ActiveEffectChanged.cs" />
<Compile Include="Events\ChangeBitmap.cs" />
<Compile Include="InjectionFactories\ILayerEditorVmFactory.cs" />
<Compile Include="InjectionFactories\IProfileEditorVmFactory.cs" />
<Compile Include="ItemBehaviours\BindableSelectedItemBehavior.cs" />
@ -301,15 +301,14 @@
<Compile Include="Models\GameSettings.cs" />
<Compile Include="Models\Interfaces\GameDataModel.cs" />
<Compile Include="Models\OverlaySettings.cs" />
<Compile Include="Models\Profiles\LayerConditionModel.cs" />
<Compile Include="Models\Profiles\LayerModel.cs" />
<Compile Include="Models\Profiles\ProfileModel.cs" />
<Compile Include="Models\Profiles\Properties\DynamicPropertiesModel.cs" />
<Compile Include="Models\Profiles\Properties\HeadsetPropertiesModel.cs" />
<Compile Include="Models\Profiles\Properties\KeyboardPropertiesModel.cs" />
<Compile Include="Models\Profiles\Properties\LayerPropertiesModel.cs" />
<Compile Include="Models\Profiles\Properties\FolderPropertiesModel.cs" />
<Compile Include="Models\Profiles\Properties\MousePropertiesModel.cs" />
<Compile Include="Modules\Effects\AudioVisualizer\AudioVisualization.cs" />
<Compile Include="Modules\Effects\Bubbles\Bubbles.cs" />
<Compile Include="Profiles\Layers\Animations\NoneAnimation.cs" />
<Compile Include="Profiles\Layers\Models\EventPropertiesModel.cs" />
<Compile Include="Profiles\Layers\Models\KeyboardEventPropertiesModel.cs" />
<Compile Include="Profiles\ProfileModel.cs" />
<Compile Include="Profiles\Layers\Models\SimplePropertiesModel.cs" />
<Compile Include="Profiles\Layers\Types\Keyboard\KeyboardPropertiesModel.cs" />
<Compile Include="Modules\Effects\AudioVisualizer\AudioVisualization.Designer.cs">
<DependentUpon>AudioVisualization.settings</DependentUpon>
<AutoGen>True</AutoGen>
@ -420,6 +419,26 @@
<Compile Include="InjectionModules\ArtemisModules.cs" />
<Compile Include="InjectionModules\BaseModules.cs" />
<Compile Include="InjectionModules\ManagerModules.cs" />
<Compile Include="Profiles\Layers\Animations\GrowAnimation.cs" />
<Compile Include="Profiles\Layers\Animations\PulseAnimation.cs" />
<Compile Include="Profiles\Layers\Animations\SlideDownAnimation.cs" />
<Compile Include="Profiles\Layers\Animations\SlideLeftAnimation.cs" />
<Compile Include="Profiles\Layers\Animations\SlideRightAnimation.cs" />
<Compile Include="Profiles\Layers\Animations\SlideUpAnimation.cs" />
<Compile Include="Profiles\Layers\Conditions\DataModelCondition.cs" />
<Compile Include="Profiles\Layers\Conditions\EventCondition.cs" />
<Compile Include="Profiles\Layers\Interfaces\ILayerAnimation.cs" />
<Compile Include="Profiles\Layers\Interfaces\ILayerCondition.cs" />
<Compile Include="Profiles\Layers\Interfaces\ILayerType.cs" />
<Compile Include="Profiles\Layers\Models\DynamicPropertiesModel.cs" />
<Compile Include="Profiles\Layers\Models\LayerConditionModel.cs" />
<Compile Include="Profiles\Layers\Models\LayerModel.cs" />
<Compile Include="Profiles\Layers\Models\LayerPropertiesModel.cs" />
<Compile Include="Profiles\Layers\Types\Folder\FolderType.cs" />
<Compile Include="Profiles\Layers\Types\Headset\HeadsetType.cs" />
<Compile Include="Profiles\Layers\Types\KeyboardGif\KeyboardGifType.cs" />
<Compile Include="Profiles\Layers\Types\Keyboard\KeyboardType.cs" />
<Compile Include="Profiles\Layers\Types\Mouse\MouseType.cs" />
<Compile Include="Properties\Annotations.cs" />
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
@ -442,6 +461,8 @@
<Compile Include="Styles\DropTargetAdorners\DropTargetMetroHighlightAdorner.cs" />
<Compile Include="Styles\DropTargetAdorners\DropTargetMetroInsertionAdorner.cs" />
<Compile Include="Utilities\ColorHelpers.cs" />
<Compile Include="Utilities\Converters\JsonConverters.cs" />
<Compile Include="Utilities\Converters\ValueConverters.cs" />
<Compile Include="Utilities\DataReaders\MmfReader.cs" />
<Compile Include="Utilities\ExtensionMethods.cs" />
<Compile Include="Utilities\GameState\GameDataReceivedEventArgs.cs" />
@ -450,8 +471,6 @@
<Compile Include="Utilities\GifImage.cs" />
<Compile Include="Utilities\ImageUtilities.cs" />
<Compile Include="Utilities\Keyboard\KeyboardHook.cs" />
<Compile Include="Utilities\Layers\AnimationUpdater.cs" />
<Compile Include="Utilities\Layers\Drawer.cs" />
<Compile Include="Utilities\Logging.cs" />
<Compile Include="Utilities\LogitechDll\DllManager.cs" />
<Compile Include="Utilities\LogitechDll\NamedPipeServer.cs" />
@ -467,11 +486,11 @@
<Compile Include="Utilities\ShellLink.cs" />
<Compile Include="Utilities\StickyValue.cs" />
<Compile Include="Utilities\Updater.cs" />
<Compile Include="Utilities\ValueConverters.cs" />
<Compile Include="ViewModels\Abstract\BaseViewModel.cs" />
<Compile Include="ViewModels\Abstract\OverlayViewModel.cs" />
<Compile Include="ViewModels\Abstract\EffectViewModel.cs" />
<Compile Include="ViewModels\Abstract\GameViewModel.cs" />
<Compile Include="ViewModels\DebugViewModel.cs" />
<Compile Include="ViewModels\EffectsViewModel.cs" />
<Compile Include="Modules\Effects\AudioVisualizer\AudioVisualizerViewModel.cs" />
<Compile Include="Modules\Effects\TypeWave\TypeWaveViewModel.cs" />
@ -482,21 +501,25 @@
<Compile Include="Modules\Games\Dota2\Dota2ViewModel.cs" />
<Compile Include="Modules\Games\RocketLeague\RocketLeagueViewModel.cs" />
<Compile Include="Modules\Games\Witcher3\Witcher3ViewModel.cs" />
<Compile Include="ViewModels\Profiles\Events\EventPropertiesViewModel.cs" />
<Compile Include="ViewModels\Profiles\ProfileViewModel.cs" />
<Compile Include="ViewModels\Profiles\Properties\KeyboardPropertiesViewModel.cs" />
<Compile Include="ViewModels\Profiles\Layers\KeyboardPropertiesViewModel.cs" />
<Compile Include="ViewModels\Profiles\LayerConditionViewModel.cs" />
<Compile Include="ViewModels\Profiles\LayerDynamicPropertiesViewModel.cs" />
<Compile Include="ViewModels\Profiles\LayerEditorViewModel.cs" />
<Compile Include="ViewModels\Profiles\Properties\LayerPropertiesViewModel.cs" />
<Compile Include="ViewModels\Profiles\Properties\HeadsetPropertiesViewModel.cs" />
<Compile Include="ViewModels\Profiles\Properties\FolderPropertiesViewModel.cs" />
<Compile Include="ViewModels\Profiles\Properties\MousePropertiesViewModel.cs" />
<Compile Include="ViewModels\Profiles\Layers\LayerPropertiesViewModel.cs" />
<Compile Include="ViewModels\Profiles\Layers\HeadsetPropertiesViewModel.cs" />
<Compile Include="ViewModels\Profiles\Layers\FolderPropertiesViewModel.cs" />
<Compile Include="ViewModels\Profiles\Layers\MousePropertiesViewModel.cs" />
<Compile Include="ViewModels\OverlaysViewModel.cs" />
<Compile Include="Modules\Overlays\VolumeDisplay\VolumeDisplayViewModel.cs" />
<Compile Include="ViewModels\Profiles\ProfileEditorViewModel.cs" />
<Compile Include="ViewModels\ShellViewModel.cs" />
<Compile Include="ViewModels\SystemTrayViewModel.cs" />
<Compile Include="ViewModels\WelcomeViewModel.cs" />
<Compile Include="Views\DebugView.xaml.cs">
<DependentUpon>DebugView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\EffectsView.xaml.cs">
<DependentUpon>EffectsView.xaml</DependentUpon>
</Compile>
@ -524,13 +547,16 @@
<Compile Include="Modules\Games\Witcher3\Witcher3View.xaml.cs">
<DependentUpon>Witcher3View.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Profiles\Properties\FolderPropertiesView.xaml.cs">
<Compile Include="Views\Profiles\Events\EventPropertiesView.xaml.cs">
<DependentUpon>EventPropertiesView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Profiles\Layers\FolderPropertiesView.xaml.cs">
<DependentUpon>FolderPropertiesView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Profiles\Properties\HeadsetPropertiesView.xaml.cs">
<Compile Include="Views\Profiles\Layers\HeadsetPropertiesView.xaml.cs">
<DependentUpon>HeadsetPropertiesView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Profiles\Properties\KeyboardPropertiesView.xaml.cs">
<Compile Include="Views\Profiles\Layers\KeyboardPropertiesView.xaml.cs">
<DependentUpon>KeyboardPropertiesView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Profiles\LayerConditionView.xaml.cs">
@ -542,7 +568,7 @@
<Compile Include="Views\Profiles\LayerEditorView.xaml.cs">
<DependentUpon>LayerEditorView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\Profiles\Properties\MousePropertiesView.xaml.cs">
<Compile Include="Views\Profiles\Layers\MousePropertiesView.xaml.cs">
<DependentUpon>MousePropertiesView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\OverlaysView.xaml.cs">
@ -660,7 +686,9 @@
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
<None Include="App.config">
<SubType>Designer</SubType>
</None>
</ItemGroup>
<ItemGroup>
<Page Include="Modules\Effects\Bubbles\BubblesView.xaml">
@ -695,6 +723,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\DebugView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\EffectsView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
@ -731,15 +763,19 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Profiles\Properties\FolderPropertiesView.xaml">
<Page Include="Views\Profiles\Events\EventPropertiesView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Profiles\Properties\HeadsetPropertiesView.xaml">
<Page Include="Views\Profiles\Layers\FolderPropertiesView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Profiles\Properties\KeyboardPropertiesView.xaml">
<Page Include="Views\Profiles\Layers\HeadsetPropertiesView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Views\Profiles\Layers\KeyboardPropertiesView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
@ -755,7 +791,7 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\Profiles\Properties\MousePropertiesView.xaml">
<Page Include="Views\Profiles\Layers\MousePropertiesView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
@ -802,7 +838,9 @@
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<ItemGroup />
<ItemGroup>
<Folder Include="Utilities\ValueConverters\" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\packages\CUE.NET.1.0.3\build\net45\CUE.NET.targets" Condition="Exists('..\packages\CUE.NET.1.0.3\build\net45\CUE.NET.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

View File

@ -5,9 +5,11 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms;
using Artemis.InjectionModules;
using Artemis.Settings;
using Artemis.Utilities;
using Artemis.ViewModels;
using Caliburn.Micro;
using Newtonsoft.Json;
using Ninject;
using Application = System.Windows.Application;
using MessageBox = System.Windows.Forms.MessageBox;
@ -22,7 +24,7 @@ namespace Artemis
public ArtemisBootstrapper()
{
// Start logging before anything else
Logging.SetupLogging(Settings.General.Default.LogLevel);
Logging.SetupLogging(General.Default.LogLevel);
CheckDuplicateInstances();
Initialize();
@ -77,6 +79,7 @@ namespace Artemis
protected override void Configure()
{
JsonConvert.DefaultSettings = () => new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.Auto};
_kernel = new StandardKernel(new BaseModules(), new ArtemisModules(), new ManagerModules());
_kernel.Bind<IWindowManager>().To<WindowManager>().InSingletonScope();
_kernel.Bind<IEventAggregator>().To<EventAggregator>().InSingletonScope();
@ -114,7 +117,7 @@ namespace Artemis
private void CheckDuplicateInstances()
{
bool aIsNewInstance;
Mutex = new Mutex(true, "ArtemisMutex", out aIsNewInstance);
Mutex = new Mutex(true, "ArtemisMutex2", out aIsNewInstance);
if (aIsNewInstance)
return;

View File

@ -4,13 +4,13 @@ using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Xml.Serialization;
using Artemis.DeviceProviders;
using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Models.Profiles.Properties;
using Artemis.Profiles;
using Artemis.Profiles.Layers.Types.Keyboard;
using Artemis.Properties;
using Artemis.Utilities;
using Newtonsoft.Json;
using NLog;
namespace Artemis.DAL
@ -65,14 +65,8 @@ namespace Artemis.DAL
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
var serializer = new XmlSerializer(typeof(ProfileModel));
// Could use a StreamWriter but should serializing fail this method doesn't ruin the existing XML file
using (var xml = new StringWriter())
{
serializer.Serialize(xml, prof);
File.WriteAllText(path + $@"\{prof.Name}.xml", xml.ToString());
}
var json = JsonConvert.SerializeObject(prof, Formatting.Indented);
File.WriteAllText(path + $@"\{prof.Name}.json", json);
}
private static List<ProfileModel> ReadProfiles()
@ -82,22 +76,18 @@ namespace Artemis.DAL
var profiles = new List<ProfileModel>();
// Create the directory structure
var profilePaths = Directory.GetFiles(ProfileFolder, "*.xml", SearchOption.AllDirectories);
var profilePaths = Directory.GetFiles(ProfileFolder, "*.json", SearchOption.AllDirectories);
// Parse the JSON files into objects and add them if they are valid
var deserializer = new XmlSerializer(typeof(ProfileModel));
foreach (var path in profilePaths)
{
try
{
using (var file = new StreamReader(path))
{
var prof = (ProfileModel) deserializer.Deserialize(file);
if (prof.GameName?.Length > 1 && prof.KeyboardSlug?.Length > 1 && prof.Name?.Length > 1)
profiles.Add(prof);
}
var prof = LoadProfileIfValid(path);
if (prof != null)
profiles.Add(prof);
}
catch (InvalidOperationException e)
catch (Exception e)
{
Logger.Error("Failed to load profile: {0} - {1}", path, e.InnerException.Message);
}
@ -144,7 +134,6 @@ namespace Artemis.DAL
((KeyboardPropertiesModel) gifLayer.Properties).GifFile = gifPath;
AddOrUpdate(demoProfile);
}
}
/// <summary>
@ -166,18 +155,17 @@ namespace Artemis.DAL
/// <returns>The loaded profile, or null if invalid</returns>
public static ProfileModel LoadProfileIfValid(string path)
{
// TODO: What exception on load failure?
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.KeyboardSlug?.Length > 1) || !(prof.Name?.Length > 1))
return null;
return prof;
}
var prof = JsonConvert.DeserializeObject<ProfileModel>(File.ReadAllText(path));
if (prof == null)
return null;
if (prof.GameName.Length < 1 || prof.KeyboardSlug.Length < 1 || prof.Name.Length < 1)
return null;
return prof;
}
catch (InvalidOperationException)
catch (Exception)
{
return null;
}
@ -186,15 +174,12 @@ namespace Artemis.DAL
/// <summary>
/// Exports the given profile to the provided path in XML
/// </summary>
/// <param name="selectedProfile">The profile to export</param>
/// <param name="prof">The profile to export</param>
/// <param name="path">The path to save the profile to</param>
public static void ExportProfile(ProfileModel selectedProfile, string path)
public static void ExportProfile(ProfileModel prof, string path)
{
var serializer = new XmlSerializer(typeof(ProfileModel));
using (var file = new StreamWriter(path))
{
serializer.Serialize(file, selectedProfile);
}
var json = JsonConvert.SerializeObject(prof);
File.WriteAllText(path, json);
}
/// <summary>
@ -208,7 +193,7 @@ namespace Artemis.DAL
return;
// Remove the old file
var path = ProfileFolder + $@"\{profile.KeyboardSlug}\{profile.GameName}\{profile.Name}.xml";
var path = ProfileFolder + $@"\{profile.KeyboardSlug}\{profile.GameName}\{profile.Name}.json";
if (File.Exists(path))
File.Delete(path);
@ -220,7 +205,7 @@ namespace Artemis.DAL
public static void DeleteProfile(ProfileModel profile)
{
// Remove the file
var path = ProfileFolder + $@"\{profile.KeyboardSlug}\{profile.GameName}\{profile.Name}.xml";
var path = ProfileFolder + $@"\{profile.KeyboardSlug}\{profile.GameName}\{profile.Name}.json";
if (File.Exists(path))
File.Delete(path);
}

View File

@ -1,8 +1,7 @@
using System.Linq;
using System;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Media;
using Artemis.Utilities;
using CUE.NET;
using CUE.NET.Devices.Generic.Enums;
using Ninject.Extensions.Logging;
@ -35,33 +34,30 @@ namespace Artemis.DeviceProviders.Corsair
CueSDK.Reinitialize();
}
public override void UpdateDevice(Brush brush)
public override void UpdateDevice(Bitmap bitmap)
{
if (!CanUse || brush == null)
if (!CanUse || bitmap == null)
return;
if (bitmap.Width != bitmap.Height)
throw new ArgumentException("Bitmap must be a perfect square");
var leds = CueSDK.HeadsetSDK.Leds.Count();
var rect = new Rect(new Size(leds*20, leds*20));
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
c.DrawRectangle(brush, null, rect);
using (var img = ImageUtilities.DrawinVisualToBitmap(visual, rect))
var step = (double) bitmap.Width/leds;
using (bitmap)
{
var ledIndex = 0;
// Color each LED according to one of the pixels
foreach (var corsairLed in CueSDK.HeadsetSDK.Leds)
{
corsairLed.Color = ledIndex == 0
? img.GetPixel(0, 0)
: img.GetPixel((ledIndex + 1)*20 - 1, (ledIndex + 1)*20 - 1);
if (ledIndex == 0)
corsairLed.Color = bitmap.GetPixel(0, 0);
else
corsairLed.Color = bitmap.GetPixel((int) ((ledIndex + 1)*step - 1),
(int) ((ledIndex + 1)*step - 1));
ledIndex++;
}
}
// Flush is required for headset to work reliably on CUE2 for some reason
CueSDK.HeadsetSDK.Update(true);
CueSDK.HeadsetSDK.Update();
}
private static bool CanInitializeSdk()

View File

@ -1,8 +1,7 @@
using System.Linq;
using System;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Media;
using Artemis.Utilities;
using CUE.NET;
using CUE.NET.Devices.Generic.Enums;
using Ninject.Extensions.Logging;
@ -35,27 +34,26 @@ namespace Artemis.DeviceProviders.Corsair
CueSDK.Reinitialize();
}
public override void UpdateDevice(Brush brush)
public override void UpdateDevice(Bitmap bitmap)
{
if (!CanUse || brush == null)
if (!CanUse || bitmap == null)
return;
if (bitmap.Width != bitmap.Height)
throw new ArgumentException("Bitmap must be a perfect square");
var leds = CueSDK.MouseSDK.Leds.Count();
var rect = new Rect(new Size(leds*20, leds*20));
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
c.DrawRectangle(brush, null, rect);
using (var img = ImageUtilities.DrawinVisualToBitmap(visual, rect))
var step = (double) bitmap.Width/leds;
using (bitmap)
{
var ledIndex = 0;
// Color each LED according to one of the pixels
foreach (var corsairLed in CueSDK.MouseSDK.Leds)
{
corsairLed.Color = ledIndex == 0
? img.GetPixel(0, 0)
: img.GetPixel((ledIndex + 1)*20 - 1, (ledIndex + 1)*20 - 1);
if (ledIndex == 0)
corsairLed.Color = bitmap.GetPixel(0, 0);
else
corsairLed.Color = bitmap.GetPixel((int) ((ledIndex + 1)*step - 1),
(int) ((ledIndex + 1)*step - 1));
ledIndex++;
}
}

View File

@ -1,5 +1,5 @@
using System.Threading.Tasks;
using System.Windows.Media;
using System.Drawing;
using System.Threading.Tasks;
namespace Artemis.DeviceProviders
{
@ -16,10 +16,10 @@ namespace Artemis.DeviceProviders
public bool CanUse { get; set; }
/// <summary>
/// Updates a non-keyboard to take the colours of the provided brush
/// Updates a non-keyboard to take the colours found in the provided bitmap
/// </summary>
/// <param name="brush"></param>
public abstract void UpdateDevice(Brush brush);
/// <param name="bitmap"></param>
public abstract void UpdateDevice(Bitmap bitmap);
/// <summary>
/// Tries to enable the device and updates CanUse accordingly
@ -32,7 +32,7 @@ namespace Artemis.DeviceProviders
public abstract void Disable();
/// <summary>
/// Tries to enable the device and updates CanUse accordingly asynchronously
/// Tries to enable the device and updates CanUse accordingly asynchronously
/// </summary>
/// <returns></returns>
public Task<bool> TryEnableAsync()

View File

@ -4,7 +4,6 @@ using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using MahApps.Metro.Controls.Dialogs;
using Brush = System.Windows.Media.Brush;
using Size = System.Windows.Size;
namespace Artemis.DeviceProviders
@ -87,7 +86,7 @@ namespace Artemis.DeviceProviders
return Task.Run(() => Enable());
}
public override void UpdateDevice(Brush brush)
public override void UpdateDevice(Bitmap bitmap)
{
throw new NotImplementedException("KeyboardProvider doesn't implement UpdateDevice, use DrawBitmap instead.");
}

View File

@ -1,19 +0,0 @@
using System.Drawing;
namespace Artemis.Events
{
public class ChangeBitmap
{
public ChangeBitmap(Bitmap bitmap)
{
Bitmap = bitmap;
}
public Bitmap Bitmap { get; private set; }
public void ChangeTextMessage(Bitmap bitmap)
{
Bitmap = bitmap;
}
}
}

View File

@ -0,0 +1,14 @@
using System.Windows.Media;
namespace Artemis.Events
{
public class RazerColorArrayChanged
{
public RazerColorArrayChanged(Color[,] colors)
{
Colors = colors;
}
public Color[,] Colors { get; set; }
}
}

View File

@ -1,5 +1,5 @@
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles;
using Artemis.Profiles.Layers.Models;
using Artemis.ViewModels.Profiles;
namespace Artemis.InjectionFactories

View File

@ -13,6 +13,14 @@ using Artemis.Modules.Games.RocketLeague;
using Artemis.Modules.Games.TheDivision;
using Artemis.Modules.Games.Witcher3;
using Artemis.Modules.Overlays.VolumeDisplay;
using Artemis.Profiles.Layers.Animations;
using Artemis.Profiles.Layers.Conditions;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Types.Folder;
using Artemis.Profiles.Layers.Types.Headset;
using Artemis.Profiles.Layers.Types.Keyboard;
using Artemis.Profiles.Layers.Types.KeyboardGif;
using Artemis.Profiles.Layers.Types.Mouse;
using Artemis.ViewModels.Abstract;
using Ninject.Modules;
@ -55,6 +63,28 @@ namespace Artemis.InjectionModules
Bind<DeviceProvider>().To<CorsairHeadsets>().InSingletonScope();
#endregion
#region Layers
// Animations
Bind<ILayerAnimation>().To<NoneAnimation>();
Bind<ILayerAnimation>().To<GrowAnimation>();
Bind<ILayerAnimation>().To<PulseAnimation>();
Bind<ILayerAnimation>().To<SlideDownAnimation>();
Bind<ILayerAnimation>().To<SlideLeftAnimation>();
Bind<ILayerAnimation>().To<SlideRightAnimation>();
Bind<ILayerAnimation>().To<SlideUpAnimation>();
// Conditions
Bind<ILayerCondition>().To<DataModelCondition>();
Bind<ILayerCondition>().To<EventCondition>();
// Types
Bind<ILayerType>().To<FolderType>();
Bind<ILayerType>().To<HeadsetType>();
Bind<ILayerType>().To<KeyboardType>();
Bind<ILayerType>().To<KeyboardGifType>();
Bind<ILayerType>().To<MouseType>();
#endregion
}
}
}

View File

@ -19,6 +19,7 @@ namespace Artemis.InjectionModules
Bind<IProfileEditorVmFactory>().ToFactory();
Bind<ILayerEditorVmFactory>().ToFactory();
Bind<ProfileViewModel>().ToSelf();
Bind<DebugViewModel>().ToSelf().InSingletonScope();
Bind<BaseViewModel>().To<WelcomeViewModel>().InSingletonScope();
Bind<BaseViewModel>().To<EffectsViewModel>().InSingletonScope();

View File

@ -6,7 +6,6 @@ using System.Timers;
using Artemis.Events;
using Caliburn.Micro;
using Ninject.Extensions.Logging;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Managers
{
@ -21,7 +20,8 @@ namespace Artemis.Managers
private readonly Timer _loopTimer;
private Bitmap _keyboardBitmap;
public LoopManager(IEventAggregator events, ILogger logger, EffectManager effectManager, DeviceManager deviceManager)
public LoopManager(IEventAggregator events, ILogger logger, EffectManager effectManager,
DeviceManager deviceManager)
{
events.Subscribe(this);
_logger = logger;
@ -48,6 +48,18 @@ namespace Artemis.Managers
_keyboardBitmap?.Dispose();
}
public void Handle(ActiveEffectChanged message)
{
if (_deviceManager.ActiveKeyboard != null && _effectManager.ActiveEffect != null)
_keyboardBitmap = _deviceManager.ActiveKeyboard.KeyboardBitmap(_effectManager.ActiveEffect.KeyboardScale);
}
public void Handle(ActiveKeyboardChanged message)
{
if (_deviceManager.ActiveKeyboard != null && _effectManager.ActiveEffect != null)
_keyboardBitmap = _deviceManager.ActiveKeyboard.KeyboardBitmap(_effectManager.ActiveEffect.KeyboardScale);
}
public Task StartAsync()
{
return Task.Run(() => Start());
@ -132,50 +144,31 @@ namespace Artemis.Managers
renderEffect.Update();
// Get ActiveEffect's bitmap
Brush mouseBrush = null;
Brush headsetBrush = null;
Bitmap mouseBitmap = null;
Bitmap headsetBitmap = null;
var mice = _deviceManager.MiceProviders.Where(m => m.CanUse).ToList();
var headsets = _deviceManager.HeadsetProviders.Where(m => m.CanUse).ToList();
using (Graphics keyboardGraphics = Graphics.FromImage(_keyboardBitmap))
if (renderEffect.Initialized)
renderEffect.Render(_keyboardBitmap, out mouseBitmap, out headsetBitmap, mice.Any(), headsets.Any());
// Draw enabled overlays on top of the renderEffect
foreach (var overlayModel in _effectManager.EnabledOverlays)
{
// Fill the bitmap's background with black to avoid trailing colors on some keyboards
keyboardGraphics.Clear(Color.Black);
if (renderEffect.Initialized)
renderEffect.Render(keyboardGraphics, out mouseBrush, out headsetBrush, mice.Any(),
headsets.Any());
// Draw enabled overlays on top of the renderEffect
foreach (var overlayModel in _effectManager.EnabledOverlays)
{
overlayModel.Update();
overlayModel.RenderOverlay(keyboardGraphics, ref mouseBrush, ref headsetBrush, mice.Any(),
headsets.Any());
}
// Update mice and headsets
foreach (var mouse in mice)
mouse.UpdateDevice(mouseBrush);
foreach (var headset in headsets)
headset.UpdateDevice(headsetBrush);
overlayModel.Update();
overlayModel.RenderOverlay(_keyboardBitmap, ref mouseBitmap, ref headsetBitmap, mice.Any(),
headsets.Any());
}
// Update mice and headsets
foreach (var mouse in mice)
mouse.UpdateDevice(mouseBitmap);
foreach (var headset in headsets)
headset.UpdateDevice(headsetBitmap);
// Update the keyboard
_deviceManager.ActiveKeyboard?.DrawBitmap(_keyboardBitmap);
}
}
public void Handle(ActiveKeyboardChanged message)
{
if (_deviceManager.ActiveKeyboard != null &&_effectManager.ActiveEffect != null)
_keyboardBitmap = _deviceManager.ActiveKeyboard.KeyboardBitmap(_effectManager.ActiveEffect.KeyboardScale);
}
public void Handle(ActiveEffectChanged message)
{
if (_deviceManager.ActiveKeyboard != null && _effectManager.ActiveEffect != null)
_keyboardBitmap = _deviceManager.ActiveKeyboard.KeyboardBitmap(_effectManager.ActiveEffect.KeyboardScale);
}
}
}

View File

@ -2,12 +2,14 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows;
using Artemis.Managers;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles;
using Artemis.Profiles;
using Artemis.Profiles.Layers.Models;
using Artemis.Profiles.Layers.Types.Headset;
using Artemis.Profiles.Layers.Types.Mouse;
using Newtonsoft.Json;
using NLog;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Models
{
@ -15,12 +17,7 @@ namespace Artemis.Models
{
public delegate void SettingsUpdateHandler(EffectSettings settings);
public bool Initialized { get; set; }
public MainManager MainManager { get; set; }
public string Name { get; set; }
public int KeyboardScale { get; set; } = 4;
private DateTime _lastTrace;
protected DateTime LastTrace;
protected EffectModel(MainManager mainManager, IDataModel dataModel)
{
@ -28,6 +25,11 @@ namespace Artemis.Models
DataModel = dataModel;
}
public bool Initialized { get; set; }
public MainManager MainManager { get; set; }
public string Name { get; set; }
public int KeyboardScale { get; set; } = 4;
// Used by profile system
public IDataModel DataModel { get; set; }
public ProfileModel Profile { get; set; }
@ -41,7 +43,8 @@ namespace Artemis.Models
public abstract void Update();
// Called after every update
public virtual void Render(Graphics keyboard, out Brush mouse, out Brush headset, bool renderMice, bool renderHeadsets)
public virtual void Render(Bitmap keyboard, out Bitmap mouse, out Bitmap headset, bool renderMice,
bool renderHeadsets)
{
mouse = null;
headset = null;
@ -52,24 +55,41 @@ namespace Artemis.Models
// Get all enabled layers who's conditions are met
var renderLayers = GetRenderLayers(renderMice, renderHeadsets);
// Trace debugging
if (DateTime.Now.AddSeconds(-2) > _lastTrace)
// Render the keyboard layer-by-layer
var keyboardRect = MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale);
using (var g = Graphics.FromImage(keyboard))
{
_lastTrace = DateTime.Now;
MainManager.Logger.Trace("Effect datamodel as JSON: \r\n{0}",
JsonConvert.SerializeObject(DataModel, Formatting.Indented));
MainManager.Logger.Trace("Effect {0} has to render {1} layers", Name, renderLayers.Count);
foreach (var renderLayer in renderLayers)
MainManager.Logger.Trace(" Layer name: {0}, layer type: {1}", renderLayer.Name,
renderLayer.LayerType);
// Fill the bitmap's background with black to avoid trailing colors on some keyboards
g.Clear(Color.Black);
Profile.DrawLayers(g, renderLayers.Where(rl => rl.MustDraw()), DataModel, keyboardRect, false, true);
}
// Render the keyboard layer-by-layer
Profile.DrawProfile(keyboard, renderLayers, DataModel, MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale), false, true);
// Render the first enabled mouse (will default to null if renderMice was false)
mouse = Profile.GenerateBrush(renderLayers.LastOrDefault(l => l.LayerType == LayerType.Mouse), DataModel);
// Render the first enabled headset (will default to null if renderHeadsets was false)
headset = Profile.GenerateBrush(renderLayers.LastOrDefault(l => l.LayerType == LayerType.Headset), DataModel);
// Render the mouse layer-by-layer
var smallRect = new Rect(0, 0, 40, 40);
mouse = new Bitmap(40, 40);
using (var g = Graphics.FromImage(mouse))
{
Profile.DrawLayers(g, renderLayers.Where(rl => rl.LayerType is MouseType), DataModel, smallRect,
false, true);
}
// Render the headset layer-by-layer
headset = new Bitmap(40, 40);
using (var g = Graphics.FromImage(headset))
{
Profile.DrawLayers(g, renderLayers.Where(rl => rl.LayerType is HeadsetType), DataModel, smallRect,
false, true);
}
// Trace debugging
if (DateTime.Now.AddSeconds(-2) <= LastTrace)
return;
LastTrace = DateTime.Now;
MainManager.Logger.Trace("Effect datamodel as JSON: \r\n{0}",
JsonConvert.SerializeObject(DataModel, Formatting.Indented));
MainManager.Logger.Trace("Effect {0} has to render {1} layers", Name, renderLayers.Count);
foreach (var renderLayer in renderLayers)
MainManager.Logger.Trace("- Layer name: {0}, layer type: {1}", renderLayer.Name, renderLayer.LayerType);
}
public abstract List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets);

View File

@ -1,6 +1,5 @@
using System.Drawing;
using Artemis.Managers;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Models
{
@ -29,7 +28,7 @@ namespace Artemis.Models
}
}
public abstract void RenderOverlay(Graphics keyboard, ref Brush mouse, ref Brush headset, bool renderMice,
public abstract void RenderOverlay(Bitmap keyboard, ref Bitmap mouse, ref Bitmap headset, bool renderMice,
bool renderHeadsets);
}
}

View File

@ -1,12 +0,0 @@
using Artemis.Models.Interfaces;
namespace Artemis.Models.Profiles.Properties
{
public class FolderPropertiesModel : LayerPropertiesModel
{
public override AppliedProperties GetAppliedProperties(IDataModel dataModel, bool ignoreDynamic = false)
{
return new AppliedProperties();
}
}
}

View File

@ -1,12 +0,0 @@
using Artemis.Models.Interfaces;
namespace Artemis.Models.Profiles.Properties
{
public class HeadsetPropertiesModel : LayerPropertiesModel
{
public override AppliedProperties GetAppliedProperties(IDataModel dataModel, bool ignoreDynamic = false)
{
return new AppliedProperties {Brush = Brush};
}
}
}

View File

@ -1,74 +0,0 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Xml.Serialization;
using Artemis.Models.Interfaces;
namespace Artemis.Models.Profiles.Properties
{
public class KeyboardPropertiesModel : LayerPropertiesModel
{
public KeyboardPropertiesModel()
{
DynamicProperties = new List<DynamicPropertiesModel>();
}
public double X { get; set; }
public double Y { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double Opacity { get; set; }
public bool Contain { get; set; }
public LayerAnimation Animation { get; set; }
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)
{
return new Rect(X*scale, Y*scale, Width*scale, Height*scale);
}
public override AppliedProperties GetAppliedProperties(IDataModel dataModel, bool ignoreDynamic = false)
{
var applied = new AppliedProperties
{
X = X,
Y = Y,
Width = Width,
Height = Height,
Opacity = Opacity,
Brush = Brush.CloneCurrentValue()
};
if (ignoreDynamic)
return applied;
foreach (var dynamicProperty in DynamicProperties)
dynamicProperty.ApplyProperty(dataModel, ref applied);
if (Math.Abs(applied.Opacity - 1) > 0.001)
{
applied.Brush = Brush.CloneCurrentValue();
applied.Brush.Opacity = applied.Opacity;
}
return applied;
}
}
public enum LayerAnimation
{
[Description("None")] None,
[Description("Slide left")] SlideLeft,
[Description("Slide right")] SlideRight,
[Description("Slide up")] SlideUp,
[Description("Slide down")] SlideDown,
[Description("Grow")] Grow,
[Description("Pulse")] Pulse
}
}

View File

@ -1,63 +0,0 @@
using System.Collections.Generic;
using System.Windows.Media;
using System.Xml.Serialization;
using Artemis.Models.Interfaces;
namespace Artemis.Models.Profiles.Properties
{
[XmlInclude(typeof(SolidColorBrush))]
[XmlInclude(typeof(LinearGradientBrush))]
[XmlInclude(typeof(RadialGradientBrush))]
[XmlInclude(typeof(MatrixTransform))]
[XmlInclude(typeof(KeyboardPropertiesModel))]
[XmlInclude(typeof(MousePropertiesModel))]
[XmlInclude(typeof(HeadsetPropertiesModel))]
[XmlInclude(typeof(FolderPropertiesModel))]
public abstract class LayerPropertiesModel
{
private Brush _brush;
protected LayerPropertiesModel()
{
Conditions = new List<LayerConditionModel>();
}
public List<LayerConditionModel> Conditions { get; set; }
public Brush Brush
{
get { return _brush; }
set
{
if (value == null)
{
_brush = null;
return;
}
if (value.IsFrozen)
{
_brush = value;
return;
}
// Clone the brush off of the UI thread and freeze it
var cloned = value.Dispatcher.Invoke(value.CloneCurrentValue);
cloned.Freeze();
_brush = cloned;
}
}
public abstract AppliedProperties GetAppliedProperties(IDataModel dataModel, bool ignoreDynamic = false);
}
public struct AppliedProperties
{
public double X { get; set; }
public double Y { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public double Opacity { get; set; }
public Brush Brush { get; set; }
}
}

View File

@ -1,12 +0,0 @@
using Artemis.Models.Interfaces;
namespace Artemis.Models.Profiles.Properties
{
public class MousePropertiesModel : LayerPropertiesModel
{
public override AppliedProperties GetAppliedProperties(IDataModel dataModel, bool ignoreDynamic = false)
{
return new AppliedProperties {Brush = Brush};
}
}
}

View File

@ -0,0 +1,28 @@
namespace Artemis.Modules.Effects.AudioVisualizer {
// This class allows you to handle specific events on the settings class:
// The SettingChanging event is raised before a setting's value is changed.
// The PropertyChanged event is raised after a setting's value is changed.
// The SettingsLoaded event is raised after the setting values are loaded.
// The SettingsSaving event is raised before the setting values are saved.
internal sealed partial class AudioVisualization {
public AudioVisualization() {
// // To add event handlers for saving and changing settings, uncomment the lines below:
//
// this.SettingChanging += this.SettingChangingEventHandler;
//
// this.SettingsSaving += this.SettingsSavingEventHandler;
//
}
private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {
// Add code to handle the SettingChangingEvent event here.
}
private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {
// Add code to handle the SettingsSaving event here.
}
}
}

View File

@ -5,13 +5,12 @@ using System.Drawing.Drawing2D;
using System.Linq;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Modules.Effects.AudioVisualizer.Utilities;
using Artemis.Profiles.Layers.Models;
using Artemis.Utilities;
using Artemis.Utilities.Keyboard;
using NAudio.CoreAudioApi;
using NAudio.Wave;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Modules.Effects.AudioVisualizer
{
@ -78,7 +77,7 @@ namespace Artemis.Modules.Effects.AudioVisualizer
ColorHelpers.ToDrawingColor(Settings.BottomColor)
},
LinearGradientMode.Vertical)
{ ContainedBrush = false, Height = 0 });
{ContainedBrush = false, Height = 0});
}
_sensitivity = Settings.Sensitivity;
_fromBottom = Settings.FromBottom;
@ -118,22 +117,22 @@ namespace Artemis.Modules.Effects.AudioVisualizer
if (SpectrumData.Count - 1 < i || SpectrumData[i] == 0)
height = 0;
else
height = (int)Math.Round(SpectrumData[i] / 2.55);
height = (int) Math.Round(SpectrumData[i]/2.55);
// Apply Sensitivity setting
height = height * _sensitivity;
height = height*_sensitivity;
var keyboardHeight =
(int)Math.Round(MainManager.DeviceManager.ActiveKeyboard.Height / 100.00 * height * KeyboardScale);
(int) Math.Round(MainManager.DeviceManager.ActiveKeyboard.Height/100.00*height*KeyboardScale);
if (keyboardHeight > SoundRectangles[i].Height)
SoundRectangles[i].Height = keyboardHeight;
else
SoundRectangles[i].Height = SoundRectangles[i].Height - Settings.FadeSpeed;
// Apply Bars setting
SoundRectangles[i].X = i * KeyboardScale;
SoundRectangles[i].X = i*KeyboardScale;
SoundRectangles[i].Width = KeyboardScale;
if (_fromBottom)
SoundRectangles[i].Y = MainManager.DeviceManager.ActiveKeyboard.Height * KeyboardScale -
SoundRectangles[i].Y = MainManager.DeviceManager.ActiveKeyboard.Height*KeyboardScale -
SoundRectangles[i].Height;
}
_generating = false;
@ -164,7 +163,7 @@ namespace Artemis.Modules.Effects.AudioVisualizer
for (x = 0; x < Lines; x++)
{
float peak = 0;
var b1 = (int)Math.Pow(2, x * 10.0 / (Lines - 1));
var b1 = (int) Math.Pow(2, x*10.0/(Lines - 1));
if (b1 > 2047)
b1 = 2047;
if (b1 <= b0)
@ -174,12 +173,12 @@ namespace Artemis.Modules.Effects.AudioVisualizer
if (peak < e.Result[1 + b0].X)
peak = e.Result[1 + b0].X;
}
var y = (int)(Math.Sqrt(peak) * 3 * 255 - 4);
var y = (int) (Math.Sqrt(peak)*3*255 - 4);
if (y > 255)
y = 255;
if (y < 0)
y = 0;
SpectrumData.Add((byte)y);
SpectrumData.Add((byte) y);
}
}
@ -188,7 +187,7 @@ namespace Artemis.Modules.Effects.AudioVisualizer
return null;
}
public override void Render(Graphics keyboard, out Brush mouse, out Brush headset, bool renderMice,
public override void Render(Bitmap keyboard, out Bitmap mouse, out Bitmap headset, bool renderMice,
bool renderHeadsets)
{
mouse = null;
@ -200,8 +199,11 @@ namespace Artemis.Modules.Effects.AudioVisualizer
// Lock the _spectrumData array while busy with it
_generating = true;
foreach (var soundRectangle in SoundRectangles)
soundRectangle.Draw(keyboard);
using (var g = Graphics.FromImage(keyboard))
{
foreach (var soundRectangle in SoundRectangles)
soundRectangle.Draw(g);
}
_generating = false;
}

View File

@ -6,11 +6,24 @@ namespace Artemis.Modules.Effects.Bubbles
{
public class Bubble
{
#region Constructors
public Bubble(Color color, int radius, Point position, Vector direction)
{
Color = color;
Radius = radius;
Position = position;
Direction = direction;
}
#endregion
#region Properties & Fields
private Brush _brush;
private Color _color;
public Color Color
{
get { return _color; }
@ -27,27 +40,15 @@ namespace Artemis.Modules.Effects.Bubbles
#endregion
#region Constructors
public Bubble(Color color, int radius, Point position, Vector direction)
{
this.Color = color;
this.Radius = radius;
this.Position = position;
this.Direction = direction;
}
#endregion
#region Methods
public void CheckCollision(Rect border)
{
if (Position.X - Radius < border.X || Position.X + Radius > border.X + border.Width)
Direction = new Vector(Direction.X * -1, Direction.Y);
Direction = new Vector(Direction.X*-1, Direction.Y);
if (Position.Y - Radius < border.Y || Position.Y + Radius > border.Y + border.Height)
Direction = new Vector(Direction.X, Direction.Y * -1);
Direction = new Vector(Direction.X, Direction.Y*-1);
}
public void Move()
@ -57,9 +58,9 @@ namespace Artemis.Modules.Effects.Bubbles
public void Draw(Graphics g)
{
g.FillEllipse(_brush, (float)Position.X - Radius, (float)Position.Y - Radius, Radius * 2, Radius * 2);
g.FillEllipse(_brush, (float) Position.X - Radius, (float) Position.Y - Radius, Radius*2, Radius*2);
}
#endregion
}
}
}

View File

@ -0,0 +1,28 @@
namespace Artemis.Modules.Effects.Bubbles {
// This class allows you to handle specific events on the settings class:
// The SettingChanging event is raised before a setting's value is changed.
// The PropertyChanged event is raised after a setting's value is changed.
// The SettingsLoaded event is raised after the setting values are loaded.
// The SettingsSaving event is raised before the setting values are saved.
internal sealed partial class Bubbles {
public Bubbles() {
// // To add event handlers for saving and changing settings, uncomment the lines below:
//
// this.SettingChanging += this.SettingChangingEventHandler;
//
// this.SettingsSaving += this.SettingsSavingEventHandler;
//
}
private void SettingChangingEventHandler(object sender, System.Configuration.SettingChangingEventArgs e) {
// Add code to handle the SettingChangingEvent event here.
}
private void SettingsSavingEventHandler(object sender, System.ComponentModel.CancelEventArgs e) {
// Add code to handle the SettingsSaving event here.
}
}
}

View File

@ -1,5 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Artemis.Modules.Effects.Bubbles" GeneratedClassName="Bubbles">
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)"
GeneratedClassNamespace="Artemis.Modules.Effects.Bubbles" GeneratedClassName="Bubbles">
<Profiles />
<Settings>
<Setting Name="IsRandomColors" Type="System.Boolean" Scope="User">

View File

@ -4,24 +4,14 @@ using System.Drawing;
using System.Windows;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Profiles.Layers.Models;
using Artemis.Utilities;
using Brush = System.Windows.Media.Brush;
using Point = System.Windows.Point;
namespace Artemis.Modules.Effects.Bubbles
{
public class BubblesModel : EffectModel
{
#region Properties & Fields
private static readonly Random _random = new Random();
private readonly List<Bubble> _bubbles = new List<Bubble>();
public BubblesSettings Settings { get; }
#endregion
#region Constructors
public BubblesModel(MainManager mainManager, BubblesSettings settings)
@ -34,27 +24,43 @@ namespace Artemis.Modules.Effects.Bubbles
#endregion
#region Properties & Fields
private static readonly Random _random = new Random();
private readonly List<Bubble> _bubbles = new List<Bubble>();
public BubblesSettings Settings { get; }
#endregion
#region Methods
public override void Enable()
{
KeyboardScale = Settings.Smoothness;
Rect rect = MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale);
var rect = MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale);
double scaleFactor = Settings.Smoothness / 25.0;
var scaleFactor = Settings.Smoothness/25.0;
for (int i = 0; i < Settings.BubbleCount; i++)
for (var i = 0; i < Settings.BubbleCount; i++)
{
Color color = Settings.IsRandomColors ? ColorHelpers.GetRandomRainbowColor() : ColorHelpers.ToDrawingColor(Settings.BubbleColor);
var color = Settings.IsRandomColors
? ColorHelpers.GetRandomRainbowColor()
: ColorHelpers.ToDrawingColor(Settings.BubbleColor);
// -Settings.MoveSpeed because we want to spawn at least one move away from borders
double initialPositionX = ((rect.Width - (Settings.BubbleSize * scaleFactor * 2) - Settings.MoveSpeed * scaleFactor) * _random.NextDouble()) + Settings.BubbleSize * scaleFactor;
double initialPositionY = ((rect.Height - (Settings.BubbleSize * scaleFactor * 2) - Settings.MoveSpeed * scaleFactor) * _random.NextDouble()) + Settings.BubbleSize * scaleFactor;
double initialDirectionX = (Settings.MoveSpeed * scaleFactor * _random.NextDouble()) * (_random.Next(1) == 0 ? -1 : 1);
double initialDirectionY = (Settings.MoveSpeed * scaleFactor - Math.Abs(initialDirectionX)) * (_random.Next(1) == 0 ? -1 : 1);
var initialPositionX = (rect.Width - Settings.BubbleSize*scaleFactor*2 - Settings.MoveSpeed*scaleFactor)*
_random.NextDouble() + Settings.BubbleSize*scaleFactor;
var initialPositionY = (rect.Height - Settings.BubbleSize*scaleFactor*2 - Settings.MoveSpeed*scaleFactor)*
_random.NextDouble() + Settings.BubbleSize*scaleFactor;
var initialDirectionX = Settings.MoveSpeed*scaleFactor*_random.NextDouble()*
(_random.Next(1) == 0 ? -1 : 1);
var initialDirectionY = (Settings.MoveSpeed*scaleFactor - Math.Abs(initialDirectionX))*
(_random.Next(1) == 0 ? -1 : 1);
_bubbles.Add(new Bubble(color, (int)Math.Round(Settings.BubbleSize * scaleFactor),
new System.Windows.Point(initialPositionX, initialPositionY), new Vector(initialDirectionX, initialDirectionY)));
_bubbles.Add(new Bubble(color, (int) Math.Round(Settings.BubbleSize*scaleFactor),
new Point(initialPositionX, initialPositionY), new Vector(initialDirectionX, initialDirectionY)));
}
Initialized = true;
@ -68,24 +74,31 @@ namespace Artemis.Modules.Effects.Bubbles
public override void Update()
{
Rect keyboardRectangle = MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale);
foreach (Bubble bubble in _bubbles)
var keyboardRectangle = MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale);
foreach (var bubble in _bubbles)
{
if (Settings.IsShiftColors)
bubble.Color = ColorHelpers.ShiftColor(bubble.Color, Settings.IsRandomColors ? (int)Math.Round(Settings.ShiftColorSpeed * _random.NextDouble()) : Settings.ShiftColorSpeed);
bubble.Color = ColorHelpers.ShiftColor(bubble.Color,
Settings.IsRandomColors
? (int) Math.Round(Settings.ShiftColorSpeed*_random.NextDouble())
: Settings.ShiftColorSpeed);
bubble.CheckCollision(keyboardRectangle);
bubble.Move();
}
}
public override void Render(Graphics keyboard, out Brush mouse, out Brush headset, bool renderMice, bool renderHeadsets)
public override void Render(Bitmap keyboard, out Bitmap mouse, out Bitmap headset, bool renderMice,
bool renderHeadsets)
{
mouse = null;
headset = null;
foreach (Bubble bubble in _bubbles)
bubble.Draw(keyboard);
using (var g = Graphics.FromImage(keyboard))
{
foreach (var bubble in _bubbles)
bubble.Draw(g);
}
}
public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
@ -95,4 +108,4 @@ namespace Artemis.Modules.Effects.Bubbles
#endregion
}
}
}

View File

@ -57,4 +57,4 @@ namespace Artemis.Modules.Effects.Bubbles
Smoothness = 25;
}
}
}
}

View File

@ -120,7 +120,7 @@
HorizontalAlignment="Right" Width="110" TickPlacement="None" TickFrequency="1"
Value="{Binding Path=EffectSettings.MoveSpeed, Mode=TwoWay}" Minimum="1" Maximum="15"
SmallChange="10" IsSnapToTickEnabled="True" />
<!-- Smoothness -->
<TextBlock Grid.Row="9" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center"
Height="16" Margin="0,9,0,10">

View File

@ -9,4 +9,4 @@ namespace Artemis.Modules.Effects.Bubbles
InitializeComponent();
}
}
}
}

View File

@ -14,7 +14,7 @@ namespace Artemis.Modules.Effects.Bubbles
events.Subscribe(this);
MainManager.EffectManager.EffectModels.Add(EffectModel);
EffectSettings = ((BubblesModel)EffectModel).Settings;
EffectSettings = ((BubblesModel) EffectModel).Settings;
}
public void Handle(ActiveEffectChanged message)
@ -22,4 +22,4 @@ namespace Artemis.Modules.Effects.Bubbles
NotifyOfPropertyChange(() => EffectEnabled);
}
}
}
}

View File

@ -1,11 +1,13 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles;
using Brush = System.Windows.Media.Brush;
using Artemis.Profiles.Layers.Models;
using Artemis.Profiles.Layers.Types.Headset;
using Artemis.Profiles.Layers.Types.Mouse;
namespace Artemis.Modules.Effects.ProfilePreview
{
@ -32,10 +34,10 @@ namespace Artemis.Modules.Effects.ProfilePreview
public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{
return Profile.GetRenderLayers<ProfilePreviewDataModel>(DataModel, renderMice, renderHeadsets, true);
return Profile.GetRenderLayers(DataModel, renderMice, renderHeadsets, true);
}
public override void Render(Graphics keyboard, out Brush mouse, out Brush headset, bool renderMice,
public override void Render(Bitmap keyboard, out Bitmap mouse, out Bitmap headset, bool renderMice,
bool renderHeadsets)
{
mouse = null;
@ -48,12 +50,30 @@ namespace Artemis.Modules.Effects.ProfilePreview
var renderLayers = GetRenderLayers(renderMice, renderHeadsets);
// Render the keyboard layer-by-layer
Profile?.DrawProfile(keyboard, renderLayers, DataModel, MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale), true, true);
// Render the first enabled mouse (will default to null if renderMice was false)
mouse = Profile?.GenerateBrush(renderLayers.LastOrDefault(l => l.LayerType == LayerType.Mouse), DataModel);
// Render the first enabled headset (will default to null if renderHeadsets was false)
headset = Profile?.GenerateBrush(renderLayers.LastOrDefault(l => l.LayerType == LayerType.Headset),
DataModel);
var keyboardRect = MainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(KeyboardScale);
using (var g = Graphics.FromImage(keyboard))
{
// Fill the bitmap's background with black to avoid trailing colors on some keyboards
g.Clear(Color.Black);
Profile.DrawLayers(g, renderLayers.Where(rl => rl.MustDraw()), DataModel, keyboardRect, true, true);
}
// Render the mouse layer-by-layer
var smallRect = new Rect(0, 0, 40, 40);
mouse = new Bitmap(40, 40);
using (var g = Graphics.FromImage(mouse))
{
Profile.DrawLayers(g, renderLayers.Where(rl => rl.LayerType is MouseType), DataModel, smallRect,
true, true);
}
// Render the headset layer-by-layer
headset = new Bitmap(40, 40);
using (var g = Graphics.FromImage(headset))
{
Profile.DrawLayers(g, renderLayers.Where(rl => rl.LayerType is HeadsetType), DataModel, smallRect,
true, true);
}
}
}

View File

@ -7,9 +7,8 @@ using Artemis.DeviceProviders.Corsair;
using Artemis.DeviceProviders.Logitech.Utilities;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Profiles.Layers.Models;
using Artemis.Utilities;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Modules.Effects.TypeWave
{
@ -46,8 +45,8 @@ namespace Artemis.Modules.Effects.TypeWave
return;
_waves.Add(Settings.IsRandomColors
? new Wave(new Point(keyMatch.PosX * KeyboardScale, keyMatch.PosY * KeyboardScale), 0, _randomColor)
: new Wave(new Point(keyMatch.PosX * KeyboardScale, keyMatch.PosY * KeyboardScale), 0,
? new Wave(new Point(keyMatch.PosX*KeyboardScale, keyMatch.PosY*KeyboardScale), 0, _randomColor)
: new Wave(new Point(keyMatch.PosX*KeyboardScale, keyMatch.PosY*KeyboardScale), 0,
ColorHelpers.ToDrawingColor(Settings.WaveColor)));
}
@ -71,12 +70,12 @@ namespace Artemis.Modules.Effects.TypeWave
// TODO: Get from settings
var fps = 25;
_waves[i].Size += Settings.SpreadSpeed * KeyboardScale;
_waves[i].Size += Settings.SpreadSpeed*KeyboardScale;
if (Settings.IsShiftColors)
_waves[i].Color = ColorHelpers.ShiftColor(_waves[i].Color, Settings.ShiftColorSpeed);
var decreaseAmount = 255 / (Settings.TimeToLive / fps);
var decreaseAmount = 255/(Settings.TimeToLive/fps);
_waves[i].Color = Color.FromArgb(
_waves[i].Color.A - decreaseAmount, _waves[i].Color.R,
_waves[i].Color.G,
@ -95,7 +94,7 @@ namespace Artemis.Modules.Effects.TypeWave
return null;
}
public override void Render(Graphics keyboard, out Brush mouse, out Brush headset, bool renderMice,
public override void Render(Bitmap keyboard, out Bitmap mouse, out Bitmap headset, bool renderMice,
bool renderHeadsets)
{
mouse = null;
@ -111,7 +110,7 @@ namespace Artemis.Modules.Effects.TypeWave
if (_waves[i].Size == 0)
continue;
var path = new GraphicsPath();
path.AddEllipse(_waves[i].Point.X - _waves[i].Size / 2, _waves[i].Point.Y - _waves[i].Size / 2,
path.AddEllipse(_waves[i].Point.X - _waves[i].Size/2, _waves[i].Point.Y - _waves[i].Size/2,
_waves[i].Size, _waves[i].Size);
Color fillColor;
@ -122,16 +121,19 @@ namespace Artemis.Modules.Effects.TypeWave
var pthGrBrush = new PathGradientBrush(path)
{
SurroundColors = new[] { _waves[i].Color },
SurroundColors = new[] {_waves[i].Color},
CenterColor = fillColor
};
keyboard.FillPath(pthGrBrush, path);
pthGrBrush.FocusScales = new PointF(0.3f, 0.8f);
using (var g = Graphics.FromImage(keyboard))
{
g.FillPath(pthGrBrush, path);
pthGrBrush.FocusScales = new PointF(0.3f, 0.8f);
keyboard.FillPath(pthGrBrush, path);
keyboard.DrawEllipse(new Pen(pthGrBrush, 1), _waves[i].Point.X - _waves[i].Size / 2,
_waves[i].Point.Y - _waves[i].Size / 2, _waves[i].Size, _waves[i].Size);
g.FillPath(pthGrBrush, path);
g.DrawEllipse(new Pen(pthGrBrush, 1), _waves[i].Point.X - _waves[i].Size/2,
_waves[i].Point.Y - _waves[i].Size/2, _waves[i].Size, _waves[i].Size);
}
}
}
}

View File

@ -14,6 +14,16 @@ namespace Artemis.Modules.Effects.WindowsProfile
public CpuDataModel Cpu { get; set; }
public PerformanceDataModel Performance { get; set; }
public Spotify Spotify { get; set; }
public CurrentTime CurrentTime { get; set; }
}
class CurrentTime
{
public int Hours24 { get; set; }
public int Hours12 { get; set; }
public int Minutes { get; set; }
public int Seconds { get; set; }
}
public class CpuDataModel

View File

@ -6,7 +6,7 @@ using System.Threading;
using System.Threading.Tasks;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Profiles.Layers.Models;
using Ninject.Extensions.Logging;
using SpotifyAPI.Local;
@ -16,7 +16,8 @@ namespace Artemis.Modules.Effects.WindowsProfile
{
[DllImport("psapi.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool GetPerformanceInfo([Out] out PerformanceInformation performanceInformation, [In] int size);
public static extern bool GetPerformanceInfo([Out] out PerformanceInformation performanceInformation,
[In] int size);
public static long GetPhysicalAvailableMemoryInMiB()
{
@ -58,6 +59,8 @@ namespace Artemis.Modules.Effects.WindowsProfile
}
}
public class WindowsProfileModel : EffectModel
{
private readonly ILogger _logger;
@ -95,6 +98,7 @@ namespace Artemis.Modules.Effects.WindowsProfile
var dataModel = (WindowsProfileDataModel) DataModel;
UpdateCpu(dataModel);
UpdateSpotify(dataModel);
UpdateDay(dataModel);
}
#region CPU
@ -161,7 +165,7 @@ namespace Artemis.Modules.Effects.WindowsProfile
public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{
return Profile.GetRenderLayers<WindowsProfileDataModel>(DataModel, renderMice, renderHeadsets, false);
return Profile.GetRenderLayers(DataModel, renderMice, renderHeadsets, false);
}
public static PerformanceCounter GetOverallPerformanceCounter()
@ -190,6 +194,19 @@ namespace Artemis.Modules.Effects.WindowsProfile
#endregion
#region Current Time
private void UpdateDay(WindowsProfileDataModel dataModel)
{
var now = DateTime.Now;
dataModel.CurrentTime.Hours24 = int.Parse(now.ToString("HH"));
dataModel.CurrentTime.Hours12 = int.Parse(now.ToString("hh"));
dataModel.CurrentTime.Minutes = int.Parse(now.ToString("mm"));
dataModel.CurrentTime.Seconds = int.Parse(now.ToString("ss"));
}
#endregion
#region Spotify
public void SetupSpotify()

View File

@ -35,102 +35,6 @@ namespace Artemis.Modules.Games.CounterStrike {
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string GameDirectory {
get {
return ((string)(this["GameDirectory"]));
}
set {
this["GameDirectory"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool AmmoEnabled {
get {
return ((bool)(this["AmmoEnabled"]));
}
set {
this["AmmoEnabled"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("#FFFF2900")]
public global::System.Windows.Media.Color AmmoMainColor {
get {
return ((global::System.Windows.Media.Color)(this["AmmoMainColor"]));
}
set {
this["AmmoMainColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("#FF26F600")]
public global::System.Windows.Media.Color AmmoSecondaryColor {
get {
return ((global::System.Windows.Media.Color)(this["AmmoSecondaryColor"]));
}
set {
this["AmmoSecondaryColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool TeamColorEnabled {
get {
return ((bool)(this["TeamColorEnabled"]));
}
set {
this["TeamColorEnabled"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool FlashEnabled {
get {
return ((bool)(this["FlashEnabled"]));
}
set {
this["FlashEnabled"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool SmokeEnabled {
get {
return ((bool)(this["SmokeEnabled"]));
}
set {
this["SmokeEnabled"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool LowHpEnabled {
get {
return ((bool)(this["LowHpEnabled"]));
}
set {
this["LowHpEnabled"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Default")]
@ -142,5 +46,17 @@ namespace Artemis.Modules.Games.CounterStrike {
this["LastProfile"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("")]
public string GameDirectory {
get {
return ((string)(this["GameDirectory"]));
}
set {
this["GameDirectory"] = value;
}
}
}
}

View File

@ -1,7 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)"
GeneratedClassNamespace="Artemis.Modules.Games.CounterStrike" GeneratedClassName="CounterStrike">
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Artemis.Modules.Games.CounterStrike" GeneratedClassName="CounterStrike">
<Profiles />
<Settings>
<Setting Name="Enabled" Type="System.Boolean" Scope="User">
@ -13,26 +11,5 @@
<Setting Name="GameDirectory" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="AmmoEnabled" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="AmmoMainColor" Type="System.Windows.Media.Color" Scope="User">
<Value Profile="(Default)">#FFFF2900</Value>
</Setting>
<Setting Name="AmmoSecondaryColor" Type="System.Windows.Media.Color" Scope="User">
<Value Profile="(Default)">#FF26F600</Value>
</Setting>
<Setting Name="TeamColorEnabled" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="FlashEnabled" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="SmokeEnabled" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="LowHpEnabled" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@ -2,7 +2,7 @@
using System.Collections.Generic;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Profiles.Layers.Models;
using Artemis.Utilities.GameState;
using Newtonsoft.Json;
using Ninject.Extensions.Logging;
@ -66,7 +66,7 @@ namespace Artemis.Modules.Games.CounterStrike
public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{
return Profile.GetRenderLayers<CounterStrikeDataModel>(DataModel, renderMice, renderHeadsets);
return Profile.GetRenderLayers(DataModel, renderMice, renderHeadsets);
}
}
}

View File

@ -1,5 +1,4 @@
using System.Windows.Media;
using Artemis.Models;
using Artemis.Models;
namespace Artemis.Modules.Games.CounterStrike
{
@ -12,29 +11,11 @@ namespace Artemis.Modules.Games.CounterStrike
public string GameDirectory { get; set; }
public bool AmmoEnabled { get; set; }
public Color AmmoMainColor { get; set; }
public Color AmmoSecondaryColor { get; set; }
public bool TeamColorEnabled { get; set; }
public bool FlashEnabled { get; set; }
public bool SmokeEnabled { get; set; }
public bool LowHpEnabled { get; set; }
public sealed override void Load()
{
Enabled = CounterStrike.Default.Enabled;
LastProfile = CounterStrike.Default.LastProfile;
GameDirectory = CounterStrike.Default.GameDirectory;
AmmoEnabled = CounterStrike.Default.AmmoEnabled;
AmmoMainColor = CounterStrike.Default.AmmoMainColor;
AmmoSecondaryColor = CounterStrike.Default.AmmoSecondaryColor;
TeamColorEnabled = CounterStrike.Default.TeamColorEnabled;
FlashEnabled = CounterStrike.Default.FlashEnabled;
SmokeEnabled = CounterStrike.Default.SmokeEnabled;
LowHpEnabled = CounterStrike.Default.LowHpEnabled;
}
public sealed override void Save()
@ -42,15 +23,6 @@ namespace Artemis.Modules.Games.CounterStrike
CounterStrike.Default.Enabled = Enabled;
CounterStrike.Default.GameDirectory = GameDirectory;
CounterStrike.Default.AmmoEnabled = AmmoEnabled;
CounterStrike.Default.AmmoMainColor = AmmoMainColor;
CounterStrike.Default.AmmoSecondaryColor = AmmoSecondaryColor;
CounterStrike.Default.TeamColorEnabled = TeamColorEnabled;
CounterStrike.Default.FlashEnabled = FlashEnabled;
CounterStrike.Default.SmokeEnabled = SmokeEnabled;
CounterStrike.Default.LowHpEnabled = LowHpEnabled;
CounterStrike.Default.Save();
}
@ -58,15 +30,6 @@ namespace Artemis.Modules.Games.CounterStrike
{
Enabled = true;
GameDirectory = string.Empty;
AmmoEnabled = true;
AmmoMainColor = Color.FromArgb(255, 38, 246, 0);
AmmoSecondaryColor = Color.FromArgb(255, 255, 41, 0);
TeamColorEnabled = true;
FlashEnabled = true;
SmokeEnabled = true;
LowHpEnabled = true;
}
}
}

View File

@ -58,125 +58,5 @@ namespace Artemis.Modules.Games.Dota2 {
this["GameDirectory"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool CanCastAbility {
get {
return ((bool)(this["CanCastAbility"]));
}
set {
this["CanCastAbility"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool ShowHealth {
get {
return ((bool)(this["ShowHealth"]));
}
set {
this["ShowHealth"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool ShowDayCycle {
get {
return ((bool)(this["ShowDayCycle"]));
}
set {
this["ShowDayCycle"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool ShowMana {
get {
return ((bool)(this["ShowMana"]));
}
set {
this["ShowMana"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("True")]
public bool ShowEvents {
get {
return ((bool)(this["ShowEvents"]));
}
set {
this["ShowEvents"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("#FFFF0000")]
public global::System.Windows.Media.Color MainColor {
get {
return ((global::System.Windows.Media.Color)(this["MainColor"]));
}
set {
this["MainColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("#FF0000FF")]
public global::System.Windows.Media.Color ManaColor {
get {
return ((global::System.Windows.Media.Color)(this["ManaColor"]));
}
set {
this["ManaColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("Default")]
public string KeyboardLayout {
get {
return ((string)(this["KeyboardLayout"]));
}
set {
this["KeyboardLayout"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("#FF00FF00")]
public global::System.Windows.Media.Color AbilityReadyColor {
get {
return ((global::System.Windows.Media.Color)(this["AbilityReadyColor"]));
}
set {
this["AbilityReadyColor"] = value;
}
}
[global::System.Configuration.UserScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.DefaultSettingValueAttribute("#FF6A5ACD")]
public global::System.Windows.Media.Color AbilityCooldownColor {
get {
return ((global::System.Windows.Media.Color)(this["AbilityCooldownColor"]));
}
set {
this["AbilityCooldownColor"] = value;
}
}
}
}

View File

@ -1,7 +1,5 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)"
GeneratedClassNamespace="Artemis.Modules.Games.Dota2" GeneratedClassName="Dota2">
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Artemis.Modules.Games.Dota2" GeneratedClassName="Dota2">
<Profiles />
<Settings>
<Setting Name="Enabled" Type="System.Boolean" Scope="User">
@ -13,35 +11,5 @@
<Setting Name="GameDirectory" Type="System.String" Scope="User">
<Value Profile="(Default)" />
</Setting>
<Setting Name="CanCastAbility" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="ShowHealth" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="ShowDayCycle" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="ShowMana" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="ShowEvents" Type="System.Boolean" Scope="User">
<Value Profile="(Default)">True</Value>
</Setting>
<Setting Name="MainColor" Type="System.Windows.Media.Color" Scope="User">
<Value Profile="(Default)">#FFFF0000</Value>
</Setting>
<Setting Name="ManaColor" Type="System.Windows.Media.Color" Scope="User">
<Value Profile="(Default)">#FF0000FF</Value>
</Setting>
<Setting Name="KeyboardLayout" Type="System.String" Scope="User">
<Value Profile="(Default)">Default</Value>
</Setting>
<Setting Name="AbilityReadyColor" Type="System.Windows.Media.Color" Scope="User">
<Value Profile="(Default)">#FF00FF00</Value>
</Setting>
<Setting Name="AbilityCooldownColor" Type="System.Windows.Media.Color" Scope="User">
<Value Profile="(Default)">#FF6A5ACD</Value>
</Setting>
</Settings>
</SettingsFile>

View File

@ -1,7 +1,7 @@
using System.Collections.Generic;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Profiles.Layers.Models;
using Artemis.Utilities.GameState;
using Newtonsoft.Json;
@ -66,7 +66,7 @@ namespace Artemis.Modules.Games.Dota2
public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{
return Profile.GetRenderLayers<Dota2DataModel>(DataModel, renderMice, renderHeadsets);
return Profile.GetRenderLayers(DataModel, renderMice, renderHeadsets);
}
}
}

View File

@ -1,5 +1,4 @@
using System.Windows.Media;
using Artemis.Models;
using Artemis.Models;
namespace Artemis.Modules.Games.Dota2
{
@ -10,74 +9,28 @@ namespace Artemis.Modules.Games.Dota2
Load();
}
public string GameDirectory { get; set; }
public override void Load()
public sealed override void Load()
{
KeyboardLayout = Dota2.Default.KeyboardLayout;
MainColor = Dota2.Default.MainColor;
ManaColor = Dota2.Default.ManaColor;
ShowHealth = Dota2.Default.ShowHealth;
CanCastAbility = Dota2.Default.CanCastAbility;
Enabled = Dota2.Default.Enabled;
GameDirectory = Dota2.Default.GameDirectory;
ShowDayCycle = Dota2.Default.ShowDayCycle;
ShowMana = Dota2.Default.ShowMana;
ShowEvents = Dota2.Default.ShowEvents;
AbilityReadyColor = Dota2.Default.AbilityReadyColor;
AbilityCooldownColor = Dota2.Default.AbilityCooldownColor;
}
public override void Save()
public sealed override void Save()
{
Dota2.Default.Enabled = Enabled;
Dota2.Default.LastProfile = LastProfile;
Dota2.Default.GameDirectory = GameDirectory;
Dota2.Default.KeyboardLayout = KeyboardLayout;
Dota2.Default.MainColor = MainColor;
Dota2.Default.ManaColor = ManaColor;
Dota2.Default.ShowDayCycle = ShowDayCycle;
Dota2.Default.ShowHealth = ShowHealth;
Dota2.Default.CanCastAbility = CanCastAbility;
Dota2.Default.ShowMana = ShowMana;
Dota2.Default.ShowEvents = ShowEvents;
Dota2.Default.AbilityCooldownColor = AbilityCooldownColor;
Dota2.Default.AbilityReadyColor = AbilityReadyColor;
Dota2.Default.Save();
}
public override void ToDefault()
public sealed override void ToDefault()
{
Enabled = true;
GameDirectory = string.Empty;
KeyboardLayout = "Default";
MainColor = Color.FromArgb(255, 255, 0, 0);
ManaColor = Color.FromArgb(255, 0, 0, 255);
AbilityCooldownColor = Color.FromArgb(255, 106, 90, 205);
AbilityReadyColor = Color.FromArgb(255, 0, 255, 0);
ShowHealth = true;
CanCastAbility = true;
ShowDayCycle = true;
ShowMana = true;
ShowEvents = true;
}
#region Variables
public string GameDirectory { get; set; }
public bool CanCastAbility { get; set; }
public bool ShowHealth { get; set; }
public bool ShowDayCycle { get; set; }
public bool ShowMana { get; set; }
public bool ShowEvents { get; set; }
public Color MainColor { get; set; }
public Color ManaColor { get; set; }
public string KeyboardLayout { get; set; }
public Color AbilityCooldownColor { get; set; }
public Color AbilityReadyColor { get; set; }
#endregion
}
}

View File

@ -9,13 +9,16 @@ namespace Artemis.Modules.Games.Overwatch
public bool UltimateReady { get; set; }
public bool Ability1Ready { get; set; }
public bool Ability2Ready { get; set; }
public bool UltimateUsed { get; set; }
public bool CanChangeHero { get; set; }
}
public enum OverwatchStatus
{
Unkown,
Unknown,
InMainMenu,
InGame
InGame,
InCharacterSelect
}
public enum OverwatchCharacter

View File

@ -1,21 +1,28 @@
using System.Collections.Generic;
using System.Drawing;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Media;
using Artemis.Events;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles;
using Artemis.Profiles.Layers.Models;
using Artemis.Utilities;
using Artemis.Utilities.DataReaders;
using Caliburn.Micro;
using Color = System.Windows.Media.Color;
namespace Artemis.Modules.Games.Overwatch
{
public class OverwatchModel : GameModel
{
private readonly IEventAggregator _events;
private DateTime _characterChange;
// Using sticky values on these since they can cause flickering
private StickyValue<OverwatchStatus> _stickyStatus;
private StickyValue<bool> _stickyUltimateReady;
private StickyValue<bool> _stickyUltimateUsed;
private DateTime _ultimateReady;
private DateTime _ultimateUsed;
public OverwatchModel(IEventAggregator events, MainManager mainManager, OverwatchSettings settings)
: base(mainManager, settings, new OverwatchDataModel())
@ -27,7 +34,7 @@ namespace Artemis.Modules.Games.Overwatch
Enabled = Settings.Enabled;
Initialized = false;
MmfReader = new MmfReader("overwatchMmf");
MmfReader = new MmfReader("overwatchMmf", MainManager.Logger);
LoadOverwatchCharacters();
}
@ -46,102 +53,184 @@ namespace Artemis.Modules.Games.Overwatch
{
OverwatchCharacters = new List<CharacterColor>
{
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Genji, Color = Color.FromRgb(13, 61, 0)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Mccree, Color = Color.FromRgb(24, 1, 1)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Pharah, Color = Color.FromRgb(0, 6, 32)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Reaper, Color = Color.FromRgb(7, 0, 0)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Soldier76, Color = Color.FromRgb(3, 5, 11)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Tracer, Color = Color.FromRgb(46, 12, 0)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Bastion, Color = Color.FromRgb(6, 10, 5)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Hanzo, Color = Color.FromRgb(28, 24, 8)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Junkrat, Color = Color.FromRgb(59, 28, 0)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Mei, Color = Color.FromRgb(3, 20, 55)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Torbjörn, Color = Color.FromRgb(31, 4, 3)},
new CharacterColor
{
OverwatchCharacter = OverwatchCharacter.Widowmaker,
Color = Color.FromRgb(16, 3, 17)
},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Dva, Color = Color.FromRgb(62, 12, 32)},
new CharacterColor
{
OverwatchCharacter = OverwatchCharacter.Reinhardt,
Color = Color.FromRgb(12, 16, 16)
},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Roadhog, Color = Color.FromRgb(26, 10, 0)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Winston, Color = Color.FromRgb(17, 18, 26)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Zarya, Color = Color.FromRgb(58, 7, 24)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Lúcio, Color = Color.FromRgb(8, 35, 0)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Mercy, Color = Color.FromRgb(60, 56, 26)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Symmetra, Color = Color.FromRgb(11, 29, 37)},
new CharacterColor {OverwatchCharacter = OverwatchCharacter.Zenyatta, Color = Color.FromRgb(62, 54, 6)}
new CharacterColor {Character = OverwatchCharacter.Genji, Color = Color.FromRgb(55, 245, 0)},
new CharacterColor {Character = OverwatchCharacter.Mccree, Color = Color.FromRgb(97, 5, 5)},
new CharacterColor {Character = OverwatchCharacter.Pharah, Color = Color.FromRgb(0, 24, 128)},
new CharacterColor {Character = OverwatchCharacter.Reaper, Color = Color.FromRgb(28, 0, 2)},
new CharacterColor {Character = OverwatchCharacter.Soldier76, Color = Color.FromRgb(14, 21, 45)},
new CharacterColor {Character = OverwatchCharacter.Tracer, Color = Color.FromRgb(186, 49, 0)},
new CharacterColor {Character = OverwatchCharacter.Bastion, Color = Color.FromRgb(26, 43, 20)},
new CharacterColor {Character = OverwatchCharacter.Hanzo, Color = Color.FromRgb(113, 99, 33)},
new CharacterColor {Character = OverwatchCharacter.Junkrat, Color = Color.FromRgb(237, 113, 2)},
new CharacterColor {Character = OverwatchCharacter.Mei, Color = Color.FromRgb(15, 82, 222)},
new CharacterColor {Character = OverwatchCharacter.Torbjörn, Color = Color.FromRgb(125, 18, 12)},
new CharacterColor {Character = OverwatchCharacter.Widowmaker, Color = Color.FromRgb(65, 12, 70)},
new CharacterColor {Character = OverwatchCharacter.Dva, Color = Color.FromRgb(248, 48, 129)},
new CharacterColor {Character = OverwatchCharacter.Reinhardt, Color = Color.FromRgb(51, 65, 66)},
new CharacterColor {Character = OverwatchCharacter.Roadhog, Color = Color.FromRgb(107, 40, 2)},
new CharacterColor {Character = OverwatchCharacter.Winston, Color = Color.FromRgb(70, 73, 107)},
new CharacterColor {Character = OverwatchCharacter.Zarya, Color = Color.FromRgb(235, 28, 97)},
new CharacterColor {Character = OverwatchCharacter.Lúcio, Color = Color.FromRgb(34, 142, 2)},
new CharacterColor {Character = OverwatchCharacter.Mercy, Color = Color.FromRgb(243, 226, 106)},
new CharacterColor {Character = OverwatchCharacter.Symmetra, Color = Color.FromRgb(46, 116, 148)},
new CharacterColor {Character = OverwatchCharacter.Zenyatta, Color = Color.FromRgb(248, 218, 26)}
};
}
public override void Dispose()
{
Initialized = false;
}
public override void Enable()
{
_stickyStatus = new StickyValue<OverwatchStatus>(300);
_stickyUltimateReady = new StickyValue<bool>(350);
_stickyUltimateUsed = new StickyValue<bool>(350);
Initialized = true;
}
public override void Dispose()
{
_stickyStatus.Dispose();
_stickyUltimateReady.Dispose();
_stickyUltimateUsed.Dispose();
Initialized = false;
}
public override void Update()
{
UpdateOverwatch();
ApplyStickyValues();
}
private void ApplyStickyValues()
{
var gameDataModel = (OverwatchDataModel) DataModel;
gameDataModel.Status = _stickyStatus.Value;
gameDataModel.UltimateReady = _stickyUltimateReady.Value;
gameDataModel.UltimateUsed = _stickyUltimateUsed.Value;
}
public void UpdateOverwatch()
{
var gameDataModel = (OverwatchDataModel) DataModel;
var colors = MmfReader.GetColorArray();
if (colors == null)
return;
var bitmap = new Bitmap(22, 6);
using (var g = Graphics.FromImage(bitmap))
{
for (var y = 0; y < 6; y++)
{
for (var x = 0; x < 22; x++)
{
g.DrawRectangle(new Pen(ColorHelpers.ToDrawingColor(colors[y, x])), y, x, 1, 1);
}
}
}
_events.PublishOnUIThread(new ChangeBitmap(bitmap));
_events.PublishOnUIThread(new RazerColorArrayChanged(colors));
//MainManager.Logger.Trace("DataModel: \r\n{0}",
// JsonConvert.SerializeObject(gameDataModel, Formatting.Indented));
// Determine general game state
gameDataModel.Status = colors[0, 0].Equals(Color.FromRgb(55, 30, 0))
? OverwatchStatus.InMainMenu
: OverwatchStatus.Unkown;
ParseGameSate(gameDataModel, colors);
if (gameDataModel.Status == OverwatchStatus.InMainMenu)
// Parse the lighting
var characterMatch = ParseCharacter(gameDataModel, colors);
// Ult can't possibly be ready within 2 seconds of changing, this avoids false positives.
// Filtering on ultReady and ultUsed removes false positives from the native ultimate effects
// The control keys don't show during character select, so don't continue on those either.
if (_characterChange.AddSeconds(2) >= DateTime.Now ||
_ultimateUsed.AddSeconds(2) >= DateTime.Now ||
_ultimateReady.AddSeconds(2) >= DateTime.Now ||
_stickyStatus.Value == OverwatchStatus.InCharacterSelect)
return;
// If ingame, look for a character
var characterMatch = OverwatchCharacters.FirstOrDefault(c => c.Color == colors[0, 0]);
if (characterMatch.OverwatchCharacter == OverwatchCharacter.None)
ParseSpecialKeys(gameDataModel, characterMatch, colors);
ParseAbilities(gameDataModel, colors);
}
private void ParseGameSate(OverwatchDataModel gameDataModel, Color[,] colors)
{
if (_ultimateUsed.AddSeconds(5) >= DateTime.Now)
return;
gameDataModel.Status = OverwatchStatus.InGame;
gameDataModel.Character = characterMatch.OverwatchCharacter;
if (colors[0, 0].Equals(Color.FromRgb(55, 30, 0)))
_stickyStatus.Value = OverwatchStatus.InMainMenu;
if (_stickyStatus.Value != OverwatchStatus.InMainMenu)
return;
gameDataModel.Character = OverwatchCharacter.None;
gameDataModel.Ability1Ready = false;
gameDataModel.Ability2Ready = false;
_stickyUltimateReady.Value = false;
_stickyUltimateUsed.Value = false;
}
private CharacterColor? ParseCharacter(OverwatchDataModel gameDataModel, Color[,] colors)
{
var characterMatch = OverwatchCharacters.FirstOrDefault(c => c.Color == colors[0, 20]);
// If a new character was chosen, let the other methods know
if (characterMatch.Character != gameDataModel.Character)
_characterChange = DateTime.Now;
// If no character was found, this method shouldn't continue
if (characterMatch.Character == OverwatchCharacter.None)
return characterMatch;
// If WASD isn't orange (any of them will do), player is in character select
_stickyStatus.Value = ControlsShown(colors) ? OverwatchStatus.InGame : OverwatchStatus.InCharacterSelect;
// Update the datamodel
gameDataModel.Character = characterMatch.Character;
return characterMatch;
}
private bool ControlsShown(Color[,] colors)
{
var keyColor = Color.FromRgb(222, 153, 0);
return colors[2, 3] == keyColor || colors[3, 2] == keyColor ||
colors[3, 3] == keyColor || colors[3, 4] == keyColor;
}
private void ParseSpecialKeys(OverwatchDataModel gameDataModel, CharacterColor? characterMatch, Color[,] colors)
{
if (characterMatch == null || characterMatch.Value.Character == OverwatchCharacter.None)
return;
// Ability1 is ready when LShift is lid
gameDataModel.Ability1Ready = colors[4, 1].Equals(Color.FromRgb(4, 141, 144));
// Ability2 is ready when E is lid
gameDataModel.Ability2Ready = colors[2, 4].Equals(Color.FromRgb(4, 141, 144));
// Ultimate is ready when Q is blinking
gameDataModel.UltimateReady = !characterMatch.Color.Equals(colors[2, 2]);
var charCol = characterMatch.Value.Color;
var backlidColor = Color.FromRgb((byte) (charCol.R*0.25), (byte) (charCol.G*0.25), (byte) (charCol.B*0.25));
var ultReady = !backlidColor.Equals(colors[2, 2]);
if (_ultimateUsed.AddSeconds(15) <= DateTime.Now)
{
// Player can change hero if H is blinking
gameDataModel.CanChangeHero = !colors[3, 7].Equals(backlidColor);
if (!_stickyUltimateReady.Value && ultReady && ControlsShown(colors))
{
_ultimateReady = DateTime.Now;
_stickyUltimateReady.Value = true;
}
}
// If ult no longer ready but it was ready before, it was used.
if (_stickyUltimateReady.Value && !ultReady)
{
_stickyUltimateReady.Value = false;
if (_ultimateUsed.AddSeconds(15) <= DateTime.Now)
_ultimateUsed = DateTime.Now;
}
// UltimateUsed is true for 10 seconds after ultimate went on cooldown
if (_ultimateUsed != DateTime.MinValue)
_stickyUltimateUsed.Value = _ultimateUsed.AddSeconds(10) >= DateTime.Now;
}
private void ParseAbilities(OverwatchDataModel gameDataModel, Color[,] colors)
{
gameDataModel.Ability1Ready = colors[4, 1].Equals(Color.FromRgb(4, 141, 144));
gameDataModel.Ability2Ready = colors[2, 4].Equals(Color.FromRgb(4, 141, 144));
}
public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{
return Profile.GetRenderLayers<OverwatchDataModel>(DataModel, renderMice, renderHeadsets);
return Profile.GetRenderLayers(DataModel, renderMice, renderHeadsets);
}
}
public struct CharacterColor
{
public OverwatchCharacter OverwatchCharacter { get; set; }
public OverwatchCharacter Character { get; set; }
public Color Color { get; set; }
}
}

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Profiles.Layers.Models;
using Artemis.Settings;
using Artemis.Utilities;
using Artemis.Utilities.Memory;
@ -66,11 +66,20 @@ namespace Artemis.Modules.Games.RocketLeague
((RocketLeagueDataModel) DataModel).Boost = 0;
if (((RocketLeagueDataModel) DataModel).Boost > 100)
((RocketLeagueDataModel) DataModel).Boost = 100;
if (DateTime.Now.AddSeconds(-2) <= LastTrace)
return;
MainManager.Logger.Trace("Offsets as JSON: \r\n{0}",
JsonConvert.SerializeObject(_pointer.GameAddresses, Formatting.Indented));
MainManager.Logger.Trace("RL specific offsets: {0}", offsets);
MainManager.Logger.Trace("Boost address: {0}", boostAddress);
MainManager.Logger.Trace("Boost float: {0}", boostFloat);
}
public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{
return Profile.GetRenderLayers<RocketLeagueDataModel>(DataModel, renderMice, renderHeadsets);
return Profile.GetRenderLayers(DataModel, renderMice, renderHeadsets);
}
}
}

View File

@ -3,7 +3,7 @@ using System.Threading;
using System.Threading.Tasks;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Profiles.Layers.Models;
using Artemis.Utilities;
using Artemis.Utilities.LogitechDll;
@ -131,7 +131,7 @@ namespace Artemis.Modules.Games.TheDivision
public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{
return Profile.GetRenderLayers<TheDivisionDataModel>(DataModel, renderMice, renderHeadsets);
return Profile.GetRenderLayers(DataModel, renderMice, renderHeadsets);
}
}
}

View File

@ -1,20 +1,19 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Profiles.Layers.Models;
namespace Artemis.Modules.Games.Witcher3
{
public class Witcher3Model : GameModel
{
private readonly Stopwatch _updateSw;
private readonly Regex _configRegex;
private readonly Stopwatch _updateSw;
private string _witcherSettings;
public Witcher3Model(MainManager mainManager, Witcher3Settings settings)
@ -139,7 +138,7 @@ namespace Artemis.Modules.Games.Witcher3
public override List<LayerModel> GetRenderLayers(bool renderMice, bool renderHeadsets)
{
return Profile.GetRenderLayers<Witcher3DataModel>(DataModel, renderMice, renderHeadsets);
return Profile.GetRenderLayers(DataModel, renderMice, renderHeadsets);
}
}
}

View File

@ -4,9 +4,8 @@ using System.Runtime.InteropServices;
using System.Windows.Forms;
using Artemis.Managers;
using Artemis.Models;
using Artemis.Models.Profiles;
using Artemis.Profiles.Layers.Models;
using NAudio.CoreAudioApi;
using Brush = System.Windows.Media.Brush;
namespace Artemis.Modules.Overlays.VolumeDisplay
{
@ -46,10 +45,10 @@ namespace Artemis.Modules.Overlays.VolumeDisplay
if (VolumeDisplay.Ttl < 1)
return;
var decreaseAmount = 500 / fps;
var decreaseAmount = 500/fps;
VolumeDisplay.Ttl = VolumeDisplay.Ttl - decreaseAmount;
if (VolumeDisplay.Ttl < 128)
VolumeDisplay.Transparancy = (byte)(VolumeDisplay.Transparancy - 20);
VolumeDisplay.Transparancy = (byte) (VolumeDisplay.Transparancy - 20);
try
{
@ -57,7 +56,7 @@ namespace Artemis.Modules.Overlays.VolumeDisplay
var volumeFloat =
enumerator.GetDefaultAudioEndpoint(DataFlow.Render, Role.Console)
.AudioEndpointVolume.MasterVolumeLevelScalar;
VolumeDisplay.Volume = (int)(volumeFloat * 100);
VolumeDisplay.Volume = (int) (volumeFloat*100);
}
catch (COMException)
{
@ -78,11 +77,16 @@ namespace Artemis.Modules.Overlays.VolumeDisplay
VolumeDisplay.Transparancy = 255;
}
public override void RenderOverlay(Graphics keyboard, ref Brush mouse, ref Brush headset, bool renderMice,
public override void RenderOverlay(Bitmap keyboard, ref Bitmap mouse, ref Bitmap headset, bool renderMice,
bool renderHeadsets)
{
if (MainManager.DeviceManager.ActiveKeyboard != null && VolumeDisplay != null && VolumeDisplay.Ttl >= 1)
VolumeDisplay.Draw(keyboard);
if (MainManager.DeviceManager.ActiveKeyboard == null || VolumeDisplay == null || VolumeDisplay.Ttl < 1)
return;
using (var g = Graphics.FromImage(keyboard))
{
VolumeDisplay.Draw(g);
}
}
}
}

View File

@ -0,0 +1,61 @@
using System.Windows;
using System.Windows.Media;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
namespace Artemis.Profiles.Layers.Animations
{
public class GrowAnimation : ILayerAnimation
{
public string Name { get; } = "Grow";
public void Update(LayerModel layerModel, bool updateAnimations)
{
var progress = layerModel.Properties.AnimationProgress;
if (MustExpire(layerModel))
progress = 0;
progress = progress + layerModel.Properties.AnimationSpeed/2.5;
// If not previewing, store the animation progress in the actual model for the next frame
if (updateAnimations)
layerModel.Properties.AnimationProgress = progress;
}
public void Draw(LayerPropertiesModel props, LayerPropertiesModel applied, DrawingContext c)
{
if (applied.Brush == null)
return;
const int scale = 4;
// Set up variables for this frame
var rect = props.Contain
? new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale, applied.Height*scale)
: new Rect(props.X*scale, props.Y*scale, props.Width*scale, props.Height*scale);
var clip = new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale, applied.Height*scale);
// Take an offset of 4 to allow layers to slightly leave their bounds
var progress = (6.0 - props.AnimationProgress)*10.0;
if (progress < 0)
{
// Can't meddle with the original brush because it's frozen.
var brush = applied.Brush.Clone();
brush.Opacity = 1 + 0.025*progress;
if (brush.Opacity < 0)
brush.Opacity = 0;
if (brush.Opacity > 1)
brush.Opacity = 1;
applied.Brush = brush;
}
rect.Inflate(-rect.Width/100.0*progress, -rect.Height/100.0*progress);
clip.Inflate(-clip.Width/100.0*progress, -clip.Height/100.0*progress);
c.PushClip(new RectangleGeometry(clip));
c.DrawRectangle(applied.Brush, null, rect);
c.Pop();
}
public bool MustExpire(LayerModel layer) => layer.Properties.AnimationProgress > 10;
}
}

View File

@ -0,0 +1,24 @@
using System.Windows.Media;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
namespace Artemis.Profiles.Layers.Animations
{
public class NoneAnimation : ILayerAnimation
{
public string Name { get; } = "None";
public void Update(LayerModel layerModel, bool updateAnimations)
{
}
public void Draw(LayerPropertiesModel props, LayerPropertiesModel applied, DrawingContext c)
{
}
public bool MustExpire(LayerModel layer)
{
return true;
}
}
}

View File

@ -0,0 +1,50 @@
using System;
using System.Windows;
using System.Windows.Media;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
namespace Artemis.Profiles.Layers.Animations
{
public class PulseAnimation : ILayerAnimation
{
public string Name { get; } = "Pulse";
public void Update(LayerModel layerModel, bool updateAnimations)
{
var progress = layerModel.Properties.AnimationProgress;
if (MustExpire(layerModel))
progress = 0;
progress = progress + layerModel.Properties.AnimationSpeed/2;
// If not previewing, store the animation progress in the actual model for the next frame
if (updateAnimations)
layerModel.Properties.AnimationProgress = progress;
}
public void Draw(LayerPropertiesModel props, LayerPropertiesModel applied, DrawingContext c)
{
if (applied.Brush == null)
return;
const int scale = 4;
// Set up variables for this frame
var rect = props.Contain
? new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale, applied.Height*scale)
: new Rect(props.X*scale, props.Y*scale, props.Width*scale, props.Height*scale);
var clip = new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale, applied.Height*scale);
// Can't meddle with the original brush because it's frozen.
var brush = applied.Brush.Clone();
brush.Opacity = (Math.Sin(props.AnimationProgress*Math.PI) + 1)*(props.Opacity/2);
applied.Brush = brush;
c.PushClip(new RectangleGeometry(clip));
c.DrawRectangle(applied.Brush, null, rect);
c.Pop();
}
public bool MustExpire(LayerModel layer) => layer.Properties.AnimationProgress > 2;
}
}

View File

@ -0,0 +1,51 @@
using System.Windows;
using System.Windows.Media;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
namespace Artemis.Profiles.Layers.Animations
{
public class SlideDownAnimation : ILayerAnimation
{
public string Name { get; } = "Slide down";
public void Update(LayerModel layerModel, bool updateAnimations)
{
var progress = layerModel.Properties.AnimationProgress;
if (MustExpire(layerModel))
progress = 0;
progress = progress + layerModel.Properties.AnimationSpeed*2;
// If not previewing, store the animation progress in the actual model for the next frame
if (updateAnimations)
layerModel.Properties.AnimationProgress = progress;
}
public void Draw(LayerPropertiesModel props, LayerPropertiesModel applied, DrawingContext c)
{
if (applied.Brush == null)
return;
const int scale = 4;
// Set up variables for this frame
var rect = props.Contain
? new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale, applied.Height*scale)
: new Rect(props.X*scale, props.Y*scale, props.Width*scale, props.Height*scale);
var s1 = new Rect(new Point(rect.X, rect.Y + props.AnimationProgress), new Size(rect.Width, rect.Height));
var s2 = new Rect(new Point(s1.X, s1.Y - rect.Height), new Size(rect.Width, rect.Height));
var clip = new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale, applied.Height*scale);
c.PushClip(new RectangleGeometry(clip));
c.DrawRectangle(applied.Brush, null, s1);
c.DrawRectangle(applied.Brush, null, s2);
c.Pop();
}
public bool MustExpire(LayerModel layer)
{
return layer.Properties.AnimationProgress + layer.Properties.AnimationSpeed*2 >= layer.Properties.Height*4;
}
}
}

View File

@ -0,0 +1,52 @@
using System.Windows;
using System.Windows.Media;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
namespace Artemis.Profiles.Layers.Animations
{
public class SlideLeftAnimation : ILayerAnimation
{
public string Name { get; } = "Slide left";
public void Update(LayerModel layerModel, bool updateAnimations)
{
var progress = layerModel.Properties.AnimationProgress;
if (MustExpire(layerModel))
progress = 0;
progress = progress + layerModel.Properties.AnimationSpeed*2;
// If not previewing, store the animation progress in the actual model for the next frame
if (updateAnimations)
layerModel.Properties.AnimationProgress = progress;
}
public void Draw(LayerPropertiesModel props, LayerPropertiesModel applied, DrawingContext c)
{
if (applied.Brush == null)
return;
const int scale = 4;
// Set up variables for this frame
var rect = props.Contain
? new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale, applied.Height*scale)
: new Rect(props.X*scale, props.Y*scale, props.Width*scale, props.Height*scale);
var s1 = new Rect(new Point(rect.X - props.AnimationProgress, rect.Y),
new Size(rect.Width + 0.05, rect.Height));
var s2 = new Rect(new Point(s1.X + rect.Width, rect.Y), new Size(rect.Width, rect.Height));
var clip = new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale, applied.Height*scale);
c.PushClip(new RectangleGeometry(clip));
c.DrawRectangle(applied.Brush, null, s1);
c.DrawRectangle(applied.Brush, null, s2);
c.Pop();
}
public bool MustExpire(LayerModel layer)
{
return layer.Properties.AnimationProgress + layer.Properties.AnimationSpeed*2 >= layer.Properties.Width*4;
}
}
}

View File

@ -0,0 +1,51 @@
using System.Windows;
using System.Windows.Media;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
namespace Artemis.Profiles.Layers.Animations
{
public class SlideRightAnimation : ILayerAnimation
{
public string Name { get; } = "Slide right";
public void Update(LayerModel layerModel, bool updateAnimations)
{
var progress = layerModel.Properties.AnimationProgress;
if (MustExpire(layerModel))
progress = 0;
progress = progress + layerModel.Properties.AnimationSpeed*2;
// If not previewing, store the animation progress in the actual model for the next frame
if (updateAnimations)
layerModel.Properties.AnimationProgress = progress;
}
public void Draw(LayerPropertiesModel props, LayerPropertiesModel applied, DrawingContext c)
{
if (applied.Brush == null)
return;
const int scale = 4;
// Set up variables for this frame
var rect = props.Contain
? new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale, applied.Height*scale)
: new Rect(props.X*scale, props.Y*scale, props.Width*scale, props.Height*scale);
var s1 = new Rect(new Point(rect.X + props.AnimationProgress, rect.Y), new Size(rect.Width, rect.Height));
var s2 = new Rect(new Point(s1.X - rect.Width, rect.Y), new Size(rect.Width + 1, rect.Height));
var clip = new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale, applied.Height*scale);
c.PushClip(new RectangleGeometry(clip));
c.DrawRectangle(applied.Brush, null, s1);
c.DrawRectangle(applied.Brush, null, s2);
c.Pop();
}
public bool MustExpire(LayerModel layer)
{
return layer.Properties.AnimationProgress + layer.Properties.AnimationSpeed*2 >= layer.Properties.Width*4;
}
}
}

View File

@ -0,0 +1,51 @@
using System.Windows;
using System.Windows.Media;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
namespace Artemis.Profiles.Layers.Animations
{
public class SlideUpAnimation : ILayerAnimation
{
public string Name { get; } = "Slide up";
public void Update(LayerModel layerModel, bool updateAnimations)
{
var progress = layerModel.Properties.AnimationProgress;
if (MustExpire(layerModel))
progress = 0;
progress = progress + layerModel.Properties.AnimationSpeed*2;
// If not previewing, store the animation progress in the actual model for the next frame
if (updateAnimations)
layerModel.Properties.AnimationProgress = progress;
}
public void Draw(LayerPropertiesModel props, LayerPropertiesModel applied, DrawingContext c)
{
if (applied.Brush == null)
return;
const int scale = 4;
// Set up variables for this frame
var rect = props.Contain
? new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale, applied.Height*scale)
: new Rect(props.X*scale, props.Y*scale, props.Width*scale, props.Height*scale);
var s1 = new Rect(new Point(rect.X, rect.Y - props.AnimationProgress), new Size(rect.Width, rect.Height));
var s2 = new Rect(new Point(s1.X, s1.Y + rect.Height), new Size(rect.Width, rect.Height));
var clip = new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale, applied.Height*scale);
c.PushClip(new RectangleGeometry(clip));
c.DrawRectangle(applied.Brush, null, s1);
c.DrawRectangle(applied.Brush, null, s2);
c.Pop();
}
public bool MustExpire(LayerModel layer)
{
return layer.Properties.AnimationProgress + layer.Properties.AnimationSpeed*2 >= layer.Properties.Height*4;
}
}
}

View File

@ -0,0 +1,15 @@
using System.Linq;
using Artemis.Models.Interfaces;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
namespace Artemis.Profiles.Layers.Conditions
{
public class DataModelCondition : ILayerCondition
{
public bool ConditionsMet(LayerModel layer, IDataModel dataModel)
{
return layer.Properties.Conditions.All(cm => cm.ConditionMet(dataModel));
}
}
}

View File

@ -0,0 +1,21 @@
using System.Linq;
using Artemis.Models.Interfaces;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
namespace Artemis.Profiles.Layers.Conditions
{
public class EventCondition : ILayerCondition
{
public bool ConditionsMet(LayerModel layer, IDataModel dataModel)
{
var conditionsMet = layer.Properties.Conditions.All(cm => cm.ConditionMet(dataModel));
layer.EventProperties.Update(layer, conditionsMet);
if (conditionsMet && layer.EventProperties.MustTrigger)
layer.EventProperties.TriggerEvent(layer);
return conditionsMet && layer.EventProperties.MustDraw;
}
}
}

View File

@ -0,0 +1,13 @@
using System.Windows.Media;
using Artemis.Profiles.Layers.Models;
namespace Artemis.Profiles.Layers.Interfaces
{
public interface ILayerAnimation
{
string Name { get; }
void Update(LayerModel layerModel, bool updateAnimations);
void Draw(LayerPropertiesModel props, LayerPropertiesModel applied, DrawingContext c);
bool MustExpire(LayerModel layer);
}
}

View File

@ -0,0 +1,10 @@
using Artemis.Models.Interfaces;
using Artemis.Profiles.Layers.Models;
namespace Artemis.Profiles.Layers.Interfaces
{
public interface ILayerCondition
{
bool ConditionsMet(LayerModel layer, IDataModel dataModel);
}
}

View File

@ -0,0 +1,57 @@
using System.Collections.Generic;
using System.Windows.Media;
using Artemis.Models.Interfaces;
using Artemis.Profiles.Layers.Models;
using Artemis.ViewModels.Profiles.Layers;
namespace Artemis.Profiles.Layers.Interfaces
{
public interface ILayerType
{
/// <summary>
/// Layer type name
/// </summary>
string Name { get; }
/// <summary>
/// Gets whether this type must be drawn on the keyboard/the editor or not
/// </summary>
bool MustDraw { get; }
/// <summary>
/// The the thumbnail for this layer type
/// </summary>
/// <param name="layer">The layer to draw the thumbnail for</param>
ImageSource DrawThumbnail(LayerModel layer);
/// <summary>
/// Draws the layer
/// </summary>
/// <param name="layer">The layer to draw</param>
/// <param name="c">The drawing context to draw with</param>
void Draw(LayerModel layer, DrawingContext c);
/// <summary>
/// Updates the provided layer layerModel according to this type
/// </summary>
/// <param name="layerModel">The layerModel to apply to</param>
/// <param name="dataModel">The datamodel to base the layer on</param>
/// <param name="isPreview">Set to true if previewing this layer</param>
void Update(LayerModel layerModel, IDataModel dataModel, bool isPreview = false);
/// <summary>
/// Sets up the layer's properties to accommodate this layerType
/// </summary>
/// <param name="layerModel"></param>
void SetupProperties(LayerModel layerModel);
/// <summary>
/// Sets up a viewmodel to accomodate this layerType
/// </summary>
/// <param name="layerPropertiesViewModel">The current viewmodel</param>
/// <param name="layerAnimations"></param>
/// <param name="dataModel">The datamodel to use in the new viewmodel</param>
/// <param name="proposedLayer">The layer to use in the new viewmodel</param>
LayerPropertiesViewModel SetupViewModel(LayerPropertiesViewModel layerPropertiesViewModel, List<ILayerAnimation> layerAnimations, IDataModel dataModel, LayerModel proposedLayer);
}
}

View File

@ -1,9 +1,8 @@
using System.ComponentModel;
using Artemis.Models.Interfaces;
using Artemis.Utilities;
using static System.Decimal;
namespace Artemis.Models.Profiles.Properties
namespace Artemis.Profiles.Layers.Models
{
public class DynamicPropertiesModel
{
@ -37,31 +36,31 @@ namespace Artemis.Models.Profiles.Properties
/// </summary>
public LayerPropertyOptions LayerPropertyOptions { get; set; }
internal void ApplyProperty(IDataModel dataModel, ref AppliedProperties properties)
internal void ApplyProperty(IDataModel dataModel, LayerPropertiesModel properties)
{
if (LayerPropertyType == LayerPropertyType.PercentageOf)
ApplyPercentageOf(dataModel, ref properties, PercentageSource);
ApplyPercentageOf(dataModel, properties, PercentageSource);
if (LayerPropertyType == LayerPropertyType.PercentageOfProperty)
ApplyPercentageOfProperty(dataModel, ref properties);
ApplyPercentageOfProperty(dataModel, properties);
}
private void ApplyPercentageOf(IDataModel dataModel, ref AppliedProperties properties, double src)
private void ApplyPercentageOf(IDataModel dataModel, LayerPropertiesModel properties, double src)
{
if (GameProperty == null)
return;
var gameProperty = dataModel.GetPropValue<int>(GameProperty);
var percentage = ToDouble(gameProperty)/src;
var percentage = decimal.ToDouble(gameProperty)/src;
if (LayerProperty == "Width")
ApplyWidth(ref properties, percentage);
ApplyWidth(properties, percentage);
else if (LayerProperty == "Height")
ApplyHeight(ref properties, percentage);
ApplyHeight(properties, percentage);
else if (LayerProperty == "Opacity")
ApplyOpacity(ref properties, percentage);
ApplyOpacity(properties, percentage);
}
private void ApplyWidth(ref AppliedProperties properties, double percentage)
private void ApplyWidth(LayerPropertiesModel properties, double percentage)
{
var newWidth = percentage*properties.Width;
var difference = properties.Width - newWidth;
@ -72,7 +71,7 @@ namespace Artemis.Models.Profiles.Properties
properties.X = properties.X + difference;
}
private void ApplyHeight(ref AppliedProperties properties, double percentage)
private void ApplyHeight(LayerPropertiesModel properties, double percentage)
{
var newHeight = percentage*properties.Height;
var difference = properties.Height - newHeight;
@ -82,7 +81,7 @@ namespace Artemis.Models.Profiles.Properties
properties.Y = properties.Y + difference;
}
private void ApplyOpacity(ref AppliedProperties properties, double percentage)
private void ApplyOpacity(LayerPropertiesModel properties, double percentage)
{
properties.Opacity = percentage*properties.Opacity;
if (properties.Opacity < 0.0)
@ -93,12 +92,16 @@ namespace Artemis.Models.Profiles.Properties
// Apply the inverse/decrease option
if (LayerPropertyOptions == LayerPropertyOptions.Decrease)
properties.Opacity = 1.0 - properties.Opacity;
var brush = properties.Brush.Clone();
brush.Opacity = properties.Opacity;
properties.Brush = brush;
}
private void ApplyPercentageOfProperty(IDataModel dataModel, ref AppliedProperties properties)
private void ApplyPercentageOfProperty(IDataModel dataModel, LayerPropertiesModel properties)
{
var value = dataModel.GetPropValue<int>(PercentageProperty);
ApplyPercentageOf(dataModel, ref properties, value);
ApplyPercentageOf(dataModel, properties, value);
}
}

View File

@ -0,0 +1,49 @@
using System;
using Newtonsoft.Json;
namespace Artemis.Profiles.Layers.Models
{
public abstract class EventPropertiesModel
{
public ExpirationType ExpirationType { get; set; }
public TimeSpan Length { get; set; }
public TimeSpan TriggerDelay { get; set; }
[JsonIgnore]
public bool MustTrigger { get; set; }
[JsonIgnore]
public DateTime AnimationStart { get; set; }
[JsonIgnore]
public bool MustDraw { get; set; }
/// <summary>
/// Resets the event's properties and triggers it
/// </summary>
public abstract void TriggerEvent(LayerModel layer);
/// <summary>
/// Gets whether the event should stop
/// </summary>
/// <param name="layer"></param>
/// <returns></returns>
public abstract bool MustStop(LayerModel layer);
// Called every frame, if parent conditions met.
public void Update(LayerModel layerModel, bool conditionsMet)
{
if (MustStop(layerModel))
MustDraw = false;
if (!conditionsMet)
MustTrigger = true;
}
}
public enum ExpirationType
{
Time,
Animation
}
}

View File

@ -0,0 +1,47 @@
using System;
using Artemis.Profiles.Layers.Types.Keyboard;
using Artemis.Profiles.Layers.Types.KeyboardGif;
namespace Artemis.Profiles.Layers.Models
{
public class KeyboardEventPropertiesModel : EventPropertiesModel
{
public override void TriggerEvent(LayerModel layer)
{
var keyboardProperties = layer.Properties as KeyboardPropertiesModel;
if (keyboardProperties == null)
throw new ArgumentException("Layer's properties cannot be null " +
"and must be of type KeyboardPropertiesModel");
if (!MustTrigger)
return;
MustTrigger = false;
MustDraw = true;
keyboardProperties.AnimationProgress = 0.0;
if (layer.GifImage != null)
layer.GifImage.CurrentFrame = 0;
}
public override bool MustStop(LayerModel layer)
{
var keyboardProperties = layer.Properties as KeyboardPropertiesModel;
if (keyboardProperties == null)
throw new ArgumentException("Layer's properties cannot be null " +
"and must be of type KeyboardPropertiesModel");
switch (ExpirationType)
{
case ExpirationType.Time:
if (AnimationStart == DateTime.MinValue)
return false;
return DateTime.Now - Length > AnimationStart;
case ExpirationType.Animation:
if (layer.LayerType is KeyboardGifType)
return layer.GifImage?.CurrentFrame >= layer.GifImage?.FrameCount - 1;
return layer.LayerAnimation == null || layer.LayerAnimation.MustExpire(layer);
default:
return true;
}
}
}
}

View File

@ -1,58 +1,58 @@
using System;
using Artemis.Models.Interfaces;
using Artemis.Utilities;
using DynamicExpresso;
namespace Artemis.Models.Profiles
{
public class LayerConditionModel
{
private readonly Interpreter _interpreter;
public LayerConditionModel()
{
_interpreter = new Interpreter();
}
public string Field { get; set; }
public string Value { get; set; }
public string Operator { get; set; }
public string Type { get; set; }
public bool ConditionMet<T>(IDataModel subject)
{
if (string.IsNullOrEmpty(Field) || string.IsNullOrEmpty(Value) || string.IsNullOrEmpty(Type))
return false;
var inspect = GeneralHelpers.GetPropertyValue(subject, Field);
if (inspect == null)
return false;
// Put the subject in a list, allowing Dynamic Linq to be used.
if (Type == "String")
{
return _interpreter.Eval<bool>($"subject.{Field}.ToLower() {Operator} value",
new Parameter("subject", typeof(T), subject),
new Parameter("value", Value.ToLower()));
}
Parameter rightParam = null;
switch (Type)
{
case "Enum":
var enumType = GeneralHelpers.GetPropertyValue(subject, Field).GetType();
rightParam = new Parameter("value", Enum.Parse(enumType, Value));
break;
case "Boolean":
rightParam = new Parameter("value", bool.Parse(Value));
break;
case "Int32":
rightParam = new Parameter("value", int.Parse(Value));
break;
}
return _interpreter.Eval<bool>($"subject.{Field} {Operator} value",
new Parameter("subject", typeof(T), subject), rightParam);
}
}
using System;
using Artemis.Models.Interfaces;
using Artemis.Utilities;
using DynamicExpresso;
namespace Artemis.Profiles.Layers.Models
{
public class LayerConditionModel
{
private readonly Interpreter _interpreter;
public LayerConditionModel()
{
_interpreter = new Interpreter();
}
public string Field { get; set; }
public string Value { get; set; }
public string Operator { get; set; }
public string Type { get; set; }
public bool ConditionMet(IDataModel subject)
{
if (string.IsNullOrEmpty(Field) || string.IsNullOrEmpty(Value) || string.IsNullOrEmpty(Type))
return false;
var inspect = GeneralHelpers.GetPropertyValue(subject, Field);
if (inspect == null)
return false;
// Put the subject in a list, allowing Dynamic Linq to be used.
if (Type == "String")
{
return _interpreter.Eval<bool>($"subject.{Field}.ToLower() {Operator} value",
new Parameter("subject", subject.GetType(), subject),
new Parameter("value", Value.ToLower()));
}
Parameter rightParam = null;
switch (Type)
{
case "Enum":
var enumType = GeneralHelpers.GetPropertyValue(subject, Field).GetType();
rightParam = new Parameter("value", Enum.Parse(enumType, Value));
break;
case "Boolean":
rightParam = new Parameter("value", bool.Parse(Value));
break;
case "Int32":
rightParam = new Parameter("value", int.Parse(Value));
break;
}
return _interpreter.Eval<bool>($"subject.{Field} {Operator} value",
new Parameter("subject", subject.GetType(), subject), rightParam);
}
}
}

View File

@ -1,276 +1,259 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Media;
using System.Xml.Serialization;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles.Properties;
using Artemis.Utilities;
using Artemis.Utilities.Layers;
using Artemis.Utilities.ParentChild;
namespace Artemis.Models.Profiles
{
public class LayerModel : IChildItem<LayerModel>, IChildItem<ProfileModel>
{
public LayerModel()
{
Children = new ChildItemCollection<LayerModel, LayerModel>(this);
}
public string Name { get; set; }
public int Order { get; set; }
public LayerType LayerType { get; set; }
public bool Enabled { get; set; }
public bool Expanded { get; set; }
public LayerPropertiesModel Properties { get; set; }
public ChildItemCollection<LayerModel, LayerModel> Children { get; }
[XmlIgnore]
public ImageSource LayerImage => Drawer.DrawThumbnail(this);
[XmlIgnore]
public LayerModel Parent { get; internal set; }
[XmlIgnore]
public ProfileModel Profile { get; internal set; }
[XmlIgnore]
public GifImage GifImage { get; set; }
public bool ConditionsMet<T>(IDataModel dataModel)
{
return Enabled && Properties.Conditions.All(cm => cm.ConditionMet<T>(dataModel));
}
public void Draw(IDataModel dataModel, DrawingContext c, bool preview, bool updateAnimations)
{
if (LayerType != LayerType.Keyboard && LayerType != LayerType.KeyboardGif)
return;
// Preview simply shows the properties as they are. When not previewing they are applied
var appliedProperties = !preview
? Properties.GetAppliedProperties(dataModel)
: Properties.GetAppliedProperties(dataModel, true);
// Update animations
AnimationUpdater.UpdateAnimation((KeyboardPropertiesModel) Properties, updateAnimations);
if (LayerType == LayerType.Keyboard)
Drawer.Draw(c, (KeyboardPropertiesModel) Properties, appliedProperties);
else if (LayerType == LayerType.KeyboardGif)
GifImage = Drawer.DrawGif(c, (KeyboardPropertiesModel) Properties, appliedProperties, GifImage);
}
public Brush GenerateBrush<T>(LayerType type, IDataModel dataModel, bool preview, bool updateAnimations)
{
if (!Enabled)
return null;
if (LayerType != LayerType.Folder && LayerType != type)
return null;
// Preview simply shows the properties as they are. When not previewing they are applied
AppliedProperties appliedProperties;
if (!preview)
{
if (!ConditionsMet<T>(dataModel))
return null; // Return null when not previewing and the conditions arent met
appliedProperties = Properties.GetAppliedProperties(dataModel);
}
else
appliedProperties = Properties.GetAppliedProperties(dataModel, true);
// TODO: Mouse/headset animations
if (LayerType != LayerType.Folder)
return appliedProperties.Brush;
Brush res = null;
foreach (var layerModel in Children.OrderByDescending(l => l.Order))
{
var brush = layerModel.GenerateBrush<T>(type, dataModel, preview, updateAnimations);
if (brush != null)
res = brush;
}
return res;
}
public void SetupProperties()
{
if ((LayerType == LayerType.Keyboard || LayerType == LayerType.KeyboardGif) &&
!(Properties is KeyboardPropertiesModel))
{
Properties = new KeyboardPropertiesModel
{
Brush = new SolidColorBrush(ColorHelpers.GetRandomRainbowMediaColor()),
Animation = LayerAnimation.None,
Height = 1,
Width = 1,
X = 0,
Y = 0,
Opacity = 1
};
}
else if (LayerType == LayerType.Mouse && !(Properties is MousePropertiesModel))
Properties = new MousePropertiesModel
{
Brush = new SolidColorBrush(ColorHelpers.GetRandomRainbowMediaColor())
};
else if (LayerType == LayerType.Headset && !(Properties is HeadsetPropertiesModel))
Properties = new HeadsetPropertiesModel
{
Brush = new SolidColorBrush(ColorHelpers.GetRandomRainbowMediaColor())
};
}
public void FixOrder()
{
Children.Sort(l => l.Order);
for (var i = 0; i < Children.Count; i++)
Children[i].Order = i;
}
/// <summary>
/// Returns whether the layer meets the requirements to be drawn
/// </summary>
/// <returns></returns>
public bool MustDraw()
{
// If any of the parents are disabled, this layer must not be drawn
var parent = Parent;
while (parent != null)
{
if (!parent.Enabled)
return false;
parent = parent.Parent;
}
return Enabled && (LayerType == LayerType.Keyboard || LayerType == LayerType.KeyboardGif);
}
public IEnumerable<LayerModel> GetLayers()
{
var layers = new List<LayerModel>();
foreach (var layerModel in Children)
{
layers.Add(layerModel);
layers.AddRange(layerModel.GetLayers());
}
return layers;
}
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 void InsertBefore(LayerModel source)
{
source.Order = Order;
Insert(source);
}
public void InsertAfter(LayerModel source)
{
source.Order = Order + 1;
Insert(source);
}
private void Insert(LayerModel source)
{
if (Parent != null)
{
foreach (var child in Parent.Children.OrderBy(c => c.Order))
{
if (child.Order >= source.Order)
child.Order++;
}
Parent.Children.Add(source);
}
else if (Profile != null)
{
foreach (var layer in Profile.Layers.OrderBy(l => l.Order))
{
if (layer.Order >= source.Order)
layer.Order++;
}
Profile.Layers.Add(source);
}
}
/// <summary>
/// Generates a flat list containing all layers that must be rendered on the keyboard,
/// the first mouse layer to be rendered and the first headset layer to be rendered
/// </summary>
/// <typeparam name="T">The game data model to base the conditions on</typeparam>
/// <param name="dataModel">Instance of said game data model</param>
/// <param name="includeMice">Whether or not to include mice in the list</param>
/// <param name="includeHeadsets">Whether or not to include headsets in the list</param>
/// <param name="ignoreConditions"></param>
/// <returns>A flat list containing all layers that must be rendered</returns>
public List<LayerModel> GetRenderLayers<T>(IDataModel dataModel, bool includeMice, bool includeHeadsets,
bool ignoreConditions = false)
{
var layers = new List<LayerModel>();
foreach (var layerModel in Children.OrderByDescending(c => c.Order))
{
if (!layerModel.Enabled ||
!includeMice && layerModel.LayerType == LayerType.Mouse ||
!includeHeadsets && layerModel.LayerType == LayerType.Headset)
continue;
if (!ignoreConditions)
{
if (!layerModel.ConditionsMet<T>(dataModel))
continue;
}
layers.Add(layerModel);
layers.AddRange(layerModel.GetRenderLayers<T>(dataModel, includeMice, includeHeadsets, ignoreConditions));
}
return layers;
}
#region IChildItem<Parent> Members
LayerModel IChildItem<LayerModel>.Parent
{
get { return Parent; }
set { Parent = value; }
}
ProfileModel IChildItem<ProfileModel>.Parent
{
get { return Profile; }
set { Profile = value; }
}
#endregion
}
public enum LayerType
{
[Description("Folder")] Folder,
[Description("Keyboard")] Keyboard,
[Description("Keyboard - GIF")] KeyboardGif,
[Description("Mouse")] Mouse,
[Description("Headset")] Headset
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Media;
using Artemis.Models.Interfaces;
using Artemis.Profiles.Layers.Conditions;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Types.Headset;
using Artemis.Profiles.Layers.Types.Keyboard;
using Artemis.Profiles.Layers.Types.Mouse;
using Artemis.Utilities;
using Artemis.Utilities.ParentChild;
using Newtonsoft.Json;
namespace Artemis.Profiles.Layers.Models
{
public class LayerModel : IChildItem<LayerModel>, IChildItem<ProfileModel>
{
public LayerModel()
{
Children = new ChildItemCollection<LayerModel, LayerModel>(this);
var model = Properties as KeyboardPropertiesModel;
if (model != null)
GifImage = new GifImage(model.GifFile);
}
public ILayerType LayerType { get; set; }
public ILayerCondition LayerCondition { get; set; }
public ILayerAnimation LayerAnimation { get; set; }
public string Name { get; set; }
public int Order { get; set; }
public bool Enabled { get; set; }
public bool Expanded { get; set; }
public bool IsEvent { get; set; }
public LayerPropertiesModel Properties { get; set; }
public EventPropertiesModel EventProperties { get; set; }
public ChildItemCollection<LayerModel, LayerModel> Children { get; }
[JsonIgnore]
public LayerPropertiesModel AppliedProperties { get; set; }
[JsonIgnore]
public ImageSource LayerImage => LayerType.DrawThumbnail(this);
[JsonIgnore]
public LayerModel Parent { get; internal set; }
[JsonIgnore]
public ProfileModel Profile { get; internal set; }
[JsonIgnore]
public GifImage GifImage { get; set; }
/// <summary>
/// Checks whether this layers conditions are met.
/// If they are met and this layer is an event, this also triggers that event.
/// </summary>
/// <param name="dataModel"></param>
/// <returns></returns>
public bool ConditionsMet(IDataModel dataModel)
{
// Conditions are not even checked if the layer isn't enabled
return Enabled && LayerCondition.ConditionsMet(this, dataModel);
}
public void Update(IDataModel dataModel, bool preview, bool updateAnimations)
{
LayerType.Update(this, dataModel, preview);
LayerAnimation?.Update(this, updateAnimations);
}
public void Draw(IDataModel dataModel, DrawingContext c, bool preview, bool updateAnimations)
{
LayerType.Draw(this, c);
}
public void SetupProperties()
{
LayerType.SetupProperties(this);
// If the type is an event, set it up
if (IsEvent && EventProperties == null)
{
EventProperties = new KeyboardEventPropertiesModel
{
ExpirationType = ExpirationType.Time,
Length = new TimeSpan(0, 0, 1),
TriggerDelay = new TimeSpan(0)
};
}
}
public void FixOrder()
{
Children.Sort(l => l.Order);
for (var i = 0; i < Children.Count; i++)
Children[i].Order = i;
}
/// <summary>
/// Returns whether the layer meets the requirements to be drawn in the profile editor
/// </summary>
/// <returns></returns>
public bool MustDraw()
{
// If any of the parents are disabled, this layer must not be drawn
var parent = Parent;
while (parent != null)
{
if (!parent.Enabled)
return false;
parent = parent.Parent;
}
return Enabled && LayerType.MustDraw;
}
/// <summary>
/// Returns every descendant of this layer
/// </summary>
/// <returns></returns>
public IEnumerable<LayerModel> GetLayers()
{
var layers = new List<LayerModel>();
foreach (var layerModel in Children)
{
layers.Add(layerModel);
layers.AddRange(layerModel.GetLayers());
}
return layers;
}
/// <summary>
/// Creates a new Keyboard layer with default settings
/// </summary>
/// <returns></returns>
public static LayerModel CreateLayer()
{
return new LayerModel
{
Name = "New layer",
Enabled = true,
Order = -1,
LayerType = new KeyboardType(),
LayerCondition = new DataModelCondition(),
Properties = new KeyboardPropertiesModel
{
Brush = new SolidColorBrush(ColorHelpers.GetRandomRainbowMediaColor()),
Height = 1,
Width = 1,
X = 0,
Y = 0,
Opacity = 1
}
};
}
public void InsertBefore(LayerModel source)
{
source.Order = Order;
Insert(source);
}
public void InsertAfter(LayerModel source)
{
source.Order = Order + 1;
Insert(source);
}
private void Insert(LayerModel source)
{
if (Parent != null)
{
foreach (var child in Parent.Children.OrderBy(c => c.Order))
{
if (child.Order >= source.Order)
child.Order++;
}
Parent.Children.Add(source);
}
else if (Profile != null)
{
foreach (var layer in Profile.Layers.OrderBy(l => l.Order))
{
if (layer.Order >= source.Order)
layer.Order++;
}
Profile.Layers.Add(source);
}
}
public void Replace(LayerModel layer)
{
layer.Order = Order;
layer.Parent = null;
layer.Profile = null;
if (Parent != null)
{
Parent.Children.Add(layer);
Parent.Children.Remove(this);
}
else if (Profile != null)
{
Profile.Layers.Add(layer);
Profile.Layers.Remove(this);
}
}
/// <summary>
/// Generates a flat list containing all layers that must be rendered on the keyboard,
/// the first mouse layer to be rendered and the first headset layer to be rendered
/// </summary>
/// <typeparam name="T">The game data model to base the conditions on</typeparam>
/// <param name="dataModel">Instance of said game data model</param>
/// <param name="includeMice">Whether or not to include mice in the list</param>
/// <param name="includeHeadsets">Whether or not to include headsets in the list</param>
/// <param name="ignoreConditions"></param>
/// <returns>A flat list containing all layers that must be rendered</returns>
public List<LayerModel> GetRenderLayers(IDataModel dataModel, bool includeMice, bool includeHeadsets,
bool ignoreConditions = false)
{
var layers = new List<LayerModel>();
foreach (var layerModel in Children.OrderByDescending(c => c.Order))
{
if (!layerModel.Enabled || !includeMice && layerModel.LayerType is MouseType ||
!includeHeadsets && layerModel.LayerType is HeadsetType)
continue;
if (!ignoreConditions && !layerModel.ConditionsMet(dataModel))
continue;
layers.Add(layerModel);
layers.AddRange(layerModel.GetRenderLayers(dataModel, includeMice, includeHeadsets, ignoreConditions));
}
return layers;
}
#region IChildItem<Parent> Members
LayerModel IChildItem<LayerModel>.Parent
{
get { return Parent; }
set { Parent = value; }
}
ProfileModel IChildItem<ProfileModel>.Parent
{
get { return Profile; }
set { Profile = value; }
}
#endregion
}
}

View File

@ -0,0 +1,69 @@
using System.Collections.Generic;
using System.Windows.Media;
using Artemis.Utilities.Converters;
using Newtonsoft.Json;
namespace Artemis.Profiles.Layers.Models
{
public abstract class LayerPropertiesModel
{
public LayerPropertiesModel(LayerPropertiesModel source = null)
{
if (source == null)
return;
// Clone the source's properties onto the new properties model (useful when changing property type)
X = source.X;
Y = source.Y;
Width = source.Width;
Height = source.Height;
Contain = source.Contain;
Opacity = source.Opacity;
AnimationSpeed = source.AnimationSpeed;
Conditions = source.Conditions;
DynamicProperties = source.DynamicProperties;
Brush = source.Brush;
}
private Brush _brush;
public double X { get; set; }
public double Y { get; set; }
public double Width { get; set; }
public double Height { get; set; }
public bool Contain { get; set; }
public double Opacity { get; set; }
public double AnimationSpeed { get; set; }
public List<LayerConditionModel> Conditions { get; set; } = new List<LayerConditionModel>();
public List<DynamicPropertiesModel> DynamicProperties { get; set; } = new List<DynamicPropertiesModel>();
[JsonIgnore]
public double AnimationProgress { get; set; }
[JsonConverter(typeof(BrushJsonConverter))]
public Brush Brush
{
get { return _brush; }
set
{
if (value == null)
{
_brush = null;
return;
}
if (value.IsFrozen)
{
_brush = value;
return;
}
// Clone the brush off of the UI thread and freeze it
var cloned = value.Dispatcher.Invoke(value.CloneCurrentValue);
cloned.Freeze();
_brush = cloned;
}
}
}
}

View File

@ -0,0 +1,12 @@
namespace Artemis.Profiles.Layers.Models
{
/// <summary>
/// An empty layer properties model used by layers that don't have their own special properties
/// </summary>
public class SimplePropertiesModel : LayerPropertiesModel
{
public SimplePropertiesModel(LayerPropertiesModel properties = null) : base(properties)
{
}
}
}

View File

@ -0,0 +1,53 @@
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using Artemis.Models.Interfaces;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
using Artemis.Properties;
using Artemis.Utilities;
using Artemis.ViewModels.Profiles.Layers;
namespace Artemis.Profiles.Layers.Types.Folder
{
public class FolderType : ILayerType
{
public string Name { get; } = "Folder";
public bool MustDraw { get; } = false;
public ImageSource DrawThumbnail(LayerModel layer)
{
var thumbnailRect = new Rect(0, 0, 18, 18);
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
c.DrawImage(ImageUtilities.BitmapToBitmapImage(Resources.folder), thumbnailRect);
var image = new DrawingImage(visual.Drawing);
return image;
}
public void Draw(LayerModel layer, DrawingContext c)
{
}
public void Update(LayerModel layerModel, IDataModel dataModel, bool isPreview = false)
{
}
public void SetupProperties(LayerModel layerModel)
{
if (layerModel.Properties is SimplePropertiesModel)
return;
layerModel.Properties = new SimplePropertiesModel(layerModel.Properties);
}
public LayerPropertiesViewModel SetupViewModel(LayerPropertiesViewModel layerPropertiesViewModel,
List<ILayerAnimation> layerAnimations, IDataModel dataModel, LayerModel proposedLayer)
{
if (layerPropertiesViewModel is FolderPropertiesViewModel)
return layerPropertiesViewModel;
return new FolderPropertiesViewModel(proposedLayer, dataModel);
}
}
}

View File

@ -0,0 +1,87 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using Artemis.Models.Interfaces;
using Artemis.Profiles.Layers.Animations;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
using Artemis.Properties;
using Artemis.Utilities;
using Artemis.ViewModels.Profiles.Layers;
namespace Artemis.Profiles.Layers.Types.Headset
{
public class HeadsetType : ILayerType
{
public string Name { get; } = "Headset";
public bool MustDraw { get; } = false;
public ImageSource DrawThumbnail(LayerModel layer)
{
var thumbnailRect = new Rect(0, 0, 18, 18);
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
c.DrawImage(ImageUtilities.BitmapToBitmapImage(Resources.headset), thumbnailRect);
var image = new DrawingImage(visual.Drawing);
return image;
}
public void Draw(LayerModel layer, DrawingContext c)
{
// If an animation is present, let it handle the drawing
if (layer.LayerAnimation != null && !(layer.LayerAnimation is NoneAnimation))
{
layer.LayerAnimation.Draw(layer.Properties, layer.AppliedProperties, c);
return;
}
// Otherwise draw the rectangle with its applied dimensions and brush
var rect = new Rect(layer.AppliedProperties.X * 4,
layer.AppliedProperties.Y * 4,
layer.AppliedProperties.Width * 4,
layer.AppliedProperties.Height * 4);
c.PushClip(new RectangleGeometry(rect));
c.DrawRectangle(layer.AppliedProperties.Brush, null, rect);
c.Pop();
}
public void Update(LayerModel layerModel, IDataModel dataModel, bool isPreview = false)
{
// Headset layers are always drawn 10*10 (which is 40*40 when scaled up)
layerModel.Properties.Width = 10;
layerModel.Properties.Height = 10;
layerModel.Properties.X = 0;
layerModel.Properties.Y = 0;
layerModel.Properties.Contain = true;
layerModel.AppliedProperties = new SimplePropertiesModel(layerModel.Properties);
if (isPreview || dataModel == null)
return;
// If not previewing, apply dynamic properties according to datamodel
var props = (SimplePropertiesModel)layerModel.AppliedProperties;
foreach (var dynamicProperty in props.DynamicProperties)
dynamicProperty.ApplyProperty(dataModel, layerModel.AppliedProperties);
}
public void SetupProperties(LayerModel layerModel)
{
if (layerModel.Properties is SimplePropertiesModel)
return;
layerModel.Properties = new SimplePropertiesModel(layerModel.Properties);
}
public LayerPropertiesViewModel SetupViewModel(LayerPropertiesViewModel layerPropertiesViewModel,
List<ILayerAnimation> layerAnimations, IDataModel dataModel, LayerModel proposedLayer)
{
if (layerPropertiesViewModel is HeadsetPropertiesViewModel)
return layerPropertiesViewModel;
return new HeadsetPropertiesViewModel(proposedLayer, dataModel, layerAnimations);
}
}
}

View File

@ -0,0 +1,19 @@
using System.Windows;
using Artemis.Profiles.Layers.Models;
namespace Artemis.Profiles.Layers.Types.Keyboard
{
public class KeyboardPropertiesModel : LayerPropertiesModel
{
public KeyboardPropertiesModel(LayerPropertiesModel properties = null) : base(properties)
{
}
public string GifFile { get; set; }
public Rect GetRect(int scale = 4)
{
return new Rect(X*scale, Y*scale, Width*scale, Height*scale);
}
}
}

View File

@ -0,0 +1,100 @@
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using Artemis.Models.Interfaces;
using Artemis.Profiles.Layers.Animations;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
using Artemis.Utilities;
using Artemis.ViewModels.Profiles.Layers;
namespace Artemis.Profiles.Layers.Types.Keyboard
{
public class KeyboardType : ILayerType
{
public string Name { get; } = "Keyboard";
public bool MustDraw { get; } = true;
public ImageSource DrawThumbnail(LayerModel layer)
{
var thumbnailRect = new Rect(0, 0, 18, 18);
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
{
if (layer.Properties.Brush != null)
{
c.DrawRectangle(layer.Properties.Brush,
new Pen(new SolidColorBrush(Colors.White), 1),
thumbnailRect);
}
}
var image = new DrawingImage(visual.Drawing);
return image;
}
public void Draw(LayerModel layer, DrawingContext c)
{
// If an animation is present, let it handle the drawing
if (layer.LayerAnimation != null && !(layer.LayerAnimation is NoneAnimation))
{
layer.LayerAnimation.Draw(layer.Properties, layer.AppliedProperties, c);
return;
}
// Otherwise draw the rectangle with its layer.AppliedProperties dimensions and brush
var rect = layer.Properties.Contain
? new Rect(layer.AppliedProperties.X*4,
layer.AppliedProperties.Y*4,
layer.AppliedProperties.Width*4,
layer.AppliedProperties.Height*4)
: new Rect(layer.Properties.X*4,
layer.Properties.Y*4,
layer.Properties.Width*4,
layer.Properties.Height*4);
var clip = new Rect(layer.AppliedProperties.X*4, layer.AppliedProperties.Y*4,
layer.AppliedProperties.Width*4, layer.AppliedProperties.Height*4);
c.PushClip(new RectangleGeometry(clip));
c.DrawRectangle(layer.AppliedProperties.Brush, null, rect);
c.Pop();
}
public void Update(LayerModel layerModel, IDataModel dataModel, bool isPreview = false)
{
layerModel.AppliedProperties = new KeyboardPropertiesModel(layerModel.Properties);
if (isPreview || dataModel == null)
return;
// If not previewing, apply dynamic properties according to datamodel
var keyboardProps = (KeyboardPropertiesModel) layerModel.AppliedProperties;
foreach (var dynamicProperty in keyboardProps.DynamicProperties)
dynamicProperty.ApplyProperty(dataModel, layerModel.AppliedProperties);
}
public void SetupProperties(LayerModel layerModel)
{
if (layerModel.Properties is KeyboardPropertiesModel)
return;
layerModel.Properties = new KeyboardPropertiesModel(layerModel.Properties);
}
public LayerPropertiesViewModel SetupViewModel(LayerPropertiesViewModel layerPropertiesViewModel,
List<ILayerAnimation> layerAnimations, IDataModel dataModel, LayerModel proposedLayer)
{
var model = layerPropertiesViewModel as KeyboardPropertiesViewModel;
if (model == null)
return new KeyboardPropertiesViewModel(proposedLayer, dataModel, layerAnimations)
{
IsGif = false
};
model.IsGif = false;
return layerPropertiesViewModel;
}
}
}

View File

@ -0,0 +1,93 @@
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Windows;
using System.Windows.Media;
using Artemis.Models.Interfaces;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
using Artemis.Profiles.Layers.Types.Keyboard;
using Artemis.Properties;
using Artemis.Utilities;
using Artemis.ViewModels.Profiles.Layers;
namespace Artemis.Profiles.Layers.Types.KeyboardGif
{
internal class KeyboardGifType : ILayerType
{
public string Name { get; } = "Keyboard - GIF";
public bool MustDraw { get; } = true;
public ImageSource DrawThumbnail(LayerModel layer)
{
var thumbnailRect = new Rect(0, 0, 18, 18);
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
c.DrawImage(ImageUtilities.BitmapToBitmapImage(Resources.gif), thumbnailRect);
var image = new DrawingImage(visual.Drawing);
return image;
}
public void Draw(LayerModel layer, DrawingContext c)
{
var props = (KeyboardPropertiesModel) layer.Properties;
if (string.IsNullOrEmpty(props.GifFile))
return;
if (!File.Exists(props.GifFile))
return;
// Only reconstruct GifImage if the underlying source has changed
if (layer.GifImage == null)
layer.GifImage = new GifImage(props.GifFile);
if (layer.GifImage.Source != props.GifFile)
layer.GifImage = new GifImage(props.GifFile);
var rect = new Rect(layer.AppliedProperties.X*4,
layer.AppliedProperties.Y*4,
layer.AppliedProperties.Width*4,
layer.AppliedProperties.Height*4);
lock (layer.GifImage)
{
var draw = layer.GifImage.GetNextFrame();
c.DrawImage(ImageUtilities.BitmapToBitmapImage(new Bitmap(draw)), rect);
}
}
public void Update(LayerModel layerModel, IDataModel dataModel, bool isPreview = false)
{
layerModel.AppliedProperties = new KeyboardPropertiesModel(layerModel.Properties);
if (isPreview)
return;
// If not previewing, apply dynamic properties according to datamodel
var keyboardProps = (KeyboardPropertiesModel) layerModel.AppliedProperties;
foreach (var dynamicProperty in keyboardProps.DynamicProperties)
dynamicProperty.ApplyProperty(dataModel, layerModel.AppliedProperties);
}
public void SetupProperties(LayerModel layerModel)
{
if (layerModel.Properties is KeyboardPropertiesModel)
return;
layerModel.Properties = new KeyboardPropertiesModel(layerModel.Properties);
}
public LayerPropertiesViewModel SetupViewModel(LayerPropertiesViewModel layerPropertiesViewModel,
List<ILayerAnimation> layerAnimations, IDataModel dataModel, LayerModel proposedLayer)
{
var model = layerPropertiesViewModel as KeyboardPropertiesViewModel;
if (model == null)
return new KeyboardPropertiesViewModel(proposedLayer, dataModel, layerAnimations)
{
IsGif = true
};
model.IsGif = true;
return layerPropertiesViewModel;
}
}
}

View File

@ -0,0 +1,88 @@
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using Artemis.Models.Interfaces;
using Artemis.Profiles.Layers.Animations;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
using Artemis.Properties;
using Artemis.Utilities;
using Artemis.ViewModels.Profiles.Layers;
namespace Artemis.Profiles.Layers.Types.Mouse
{
public class MouseType : ILayerType
{
public string Name { get; } = "Mouse";
public bool MustDraw { get; } = false;
public ImageSource DrawThumbnail(LayerModel layer)
{
var thumbnailRect = new Rect(0, 0, 18, 18);
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
c.DrawImage(ImageUtilities.BitmapToBitmapImage(Resources.mouse), thumbnailRect);
var image = new DrawingImage(visual.Drawing);
return image;
}
public void Draw(LayerModel layer, DrawingContext c)
{
// If an animation is present, let it handle the drawing
if (layer.LayerAnimation != null && !(layer.LayerAnimation is NoneAnimation))
{
layer.LayerAnimation.Draw(layer.Properties, layer.AppliedProperties, c);
return;
}
// Otherwise draw the rectangle with its applied dimensions and brush
var rect = new Rect(layer.AppliedProperties.X * 4,
layer.AppliedProperties.Y * 4,
layer.AppliedProperties.Width * 4,
layer.AppliedProperties.Height * 4);
c.PushClip(new RectangleGeometry(rect));
c.DrawRectangle(layer.AppliedProperties.Brush, null, rect);
c.Pop();
}
public void Update(LayerModel layerModel, IDataModel dataModel, bool isPreview = false)
{
// Mouse layers are always drawn 10*10 (which is 40*40 when scaled up)
layerModel.Properties.Width = 10;
layerModel.Properties.Height = 10;
layerModel.Properties.X = 0;
layerModel.Properties.Y = 0;
layerModel.Properties.Contain = true;
layerModel.AppliedProperties = new SimplePropertiesModel(layerModel.Properties);
if (isPreview || dataModel == null)
return;
// If not previewing, apply dynamic properties according to datamodel
var props = (SimplePropertiesModel)layerModel.AppliedProperties;
foreach (var dynamicProperty in props.DynamicProperties)
dynamicProperty.ApplyProperty(dataModel, layerModel.AppliedProperties);
}
public void SetupProperties(LayerModel layerModel)
{
if (layerModel.Properties is SimplePropertiesModel)
return;
layerModel.Properties = new SimplePropertiesModel(layerModel.Properties);
}
public LayerPropertiesViewModel SetupViewModel(LayerPropertiesViewModel layerPropertiesViewModel,
List<ILayerAnimation> layerAnimations, IDataModel dataModel, LayerModel proposedLayer)
{
if (layerPropertiesViewModel is MousePropertiesViewModel)
return layerPropertiesViewModel;
return new MousePropertiesViewModel(proposedLayer, dataModel, layerAnimations);
}
}
}

View File

@ -1,223 +1,201 @@
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using System.Xml.Serialization;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles.Properties;
using Artemis.Utilities;
using Artemis.Utilities.ParentChild;
using Brush = System.Windows.Media.Brush;
using Color = System.Windows.Media.Color;
using Point = System.Windows.Point;
using Size = System.Windows.Size;
namespace Artemis.Models.Profiles
{
public class ProfileModel
{
public ProfileModel()
{
Layers = new ChildItemCollection<ProfileModel, LayerModel>(this);
DrawingVisual = new DrawingVisual();
}
public ChildItemCollection<ProfileModel, LayerModel> Layers { get; }
public string Name { get; set; }
public bool IsDefault { get; set; }
public string KeyboardSlug { get; set; }
public string GameName { get; set; }
[XmlIgnore]
public DrawingVisual DrawingVisual { get; set; }
protected bool Equals(ProfileModel other)
{
return string.Equals(Name, other.Name) &&
string.Equals(KeyboardSlug, other.KeyboardSlug) &&
string.Equals(GameName, other.GameName);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((ProfileModel)obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = Name?.GetHashCode() ?? 0;
hashCode = (hashCode * 397) ^ (KeyboardSlug?.GetHashCode() ?? 0);
hashCode = (hashCode * 397) ^ (GameName?.GetHashCode() ?? 0);
return hashCode;
}
}
public void FixOrder()
{
Layers.Sort(l => l.Order);
for (var i = 0; i < Layers.Count; i++)
Layers[i].Order = i;
}
public void DrawProfile<T>(Graphics keyboard, Rect keyboardRect, IDataModel dataModel, bool preview,
bool updateAnimations)
{
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
{
// Setup the DrawingVisual's size
c.PushClip(new RectangleGeometry(keyboardRect));
c.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, keyboardRect);
// Draw the layers
foreach (var layerModel in Layers.OrderByDescending(l => l.Order))
layerModel.Draw(dataModel, c, preview, updateAnimations);
// Remove the clip
c.Pop();
}
using (Bitmap bmp = ImageUtilities.DrawinVisualToBitmap(visual, keyboardRect))
keyboard.DrawImage(bmp, new PointF(0, 0));
}
public Brush GenerateBrush<T>(IDataModel dataModel, LayerType type, bool preview, bool updateAnimations)
{
Brush result = null;
// Draw the layers
foreach (var layerModel in Layers.OrderByDescending(l => l.Order))
{
var generated = layerModel.GenerateBrush<T>(type, dataModel, preview, updateAnimations);
if (generated != null)
result = generated;
}
return result;
}
/// <summary>
/// Gives all the layers and their children in a flat list
/// </summary>
public List<LayerModel> GetLayers()
{
var layers = new List<LayerModel>();
foreach (var layerModel in Layers)
{
layers.Add(layerModel);
layers.AddRange(layerModel.GetLayers());
}
return layers;
}
/// <summary>
/// Generates a flat list containing all layers that must be rendered on the keyboard,
/// the first mouse layer to be rendered and the first headset layer to be rendered
/// </summary>
/// <typeparam name="T">The game data model to base the conditions on</typeparam>
/// <param name="dataModel">Instance of said game data model</param>
/// <param name="includeMice">Whether or not to include mice in the list</param>
/// <param name="includeHeadsets">Whether or not to include headsets in the list</param>
/// <param name="ignoreConditions"></param>
/// <returns>A flat list containing all layers that must be rendered</returns>
public List<LayerModel> GetRenderLayers<T>(IDataModel dataModel, bool includeMice, bool includeHeadsets,
bool ignoreConditions = false)
{
var layers = new List<LayerModel>();
foreach (var layerModel in Layers.OrderByDescending(l => l.Order))
{
if (!layerModel.Enabled ||
!includeMice && layerModel.LayerType == LayerType.Mouse ||
!includeHeadsets && layerModel.LayerType == LayerType.Headset)
continue;
if (!ignoreConditions)
{
if (!layerModel.ConditionsMet<T>(dataModel))
continue;
}
layers.Add(layerModel);
layers.AddRange(layerModel.GetRenderLayers<T>(dataModel, includeMice, includeHeadsets, ignoreConditions));
}
return layers;
}
/// <summary>
/// Looks at all the layers wthin the profile and makes sure they are within boundaries of the given rectangle
/// </summary>
/// <param name="keyboardRectangle"></param>
public void FixBoundaries(Rect keyboardRectangle)
{
foreach (var layer in GetLayers())
{
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;
}
}
/// <summary>
/// Draw all the provided layers of type Keyboard and KeyboardGif
/// </summary>
/// <param name="keyboard">The graphics to draw on</param>
/// <param name="renderLayers">The layers to render</param>
/// <param name="dataModel">The data model to base the layer's properties on</param>
/// <param name="keyboardRect">A rectangle matching the current keyboard's size on a scale of 4, used for clipping</param>
/// <param name="preview">Indicates wheter the layer is drawn as a preview, ignoring dynamic properties</param>
/// <param name="updateAnimations">Wheter or not to update the layer's animations</param>
internal void DrawProfile(Graphics keyboard, List<LayerModel> renderLayers, IDataModel dataModel, Rect keyboardRect,
bool preview,
bool updateAnimations)
{
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
{
// Setup the DrawingVisual's size
c.PushClip(new RectangleGeometry(keyboardRect));
c.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, keyboardRect);
// Draw the layers
foreach (var layerModel in renderLayers
.Where(l => l.LayerType == LayerType.Keyboard ||
l.LayerType == LayerType.KeyboardGif))
{
layerModel.Draw(dataModel, c, preview, updateAnimations);
}
// Remove the clip
c.Pop();
}
using (Bitmap bmp = ImageUtilities.DrawinVisualToBitmap(visual, keyboardRect))
keyboard.DrawImage(bmp, new PointF(0, 0));
}
/// <summary>
/// Generates a brush out of the given layer, for usage with mice and headsets
/// </summary>
/// <param name="layerModel">The layer to base the brush on</param>
/// <param name="dataModel">The game data model to base the layer's properties on</param>
/// <returns>The generated brush</returns>
public Brush GenerateBrush(LayerModel layerModel, IDataModel dataModel)
{
return layerModel?.Properties.GetAppliedProperties(dataModel).Brush;
}
}
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows;
using System.Windows.Media;
using Artemis.Models.Interfaces;
using Artemis.Profiles.Layers.Models;
using Artemis.Profiles.Layers.Types.Headset;
using Artemis.Profiles.Layers.Types.Keyboard;
using Artemis.Profiles.Layers.Types.Mouse;
using Artemis.Utilities;
using Artemis.Utilities.ParentChild;
using Newtonsoft.Json;
using Color = System.Windows.Media.Color;
using Point = System.Windows.Point;
using Size = System.Windows.Size;
namespace Artemis.Profiles
{
public class ProfileModel
{
public ProfileModel()
{
Layers = new ChildItemCollection<ProfileModel, LayerModel>(this);
DrawingVisual = new DrawingVisual();
}
public ChildItemCollection<ProfileModel, LayerModel> Layers { get; }
public string Name { get; set; }
public bool IsDefault { get; set; }
public string KeyboardSlug { get; set; }
public string GameName { get; set; }
[JsonIgnore]
public DrawingVisual DrawingVisual { get; set; }
public void FixOrder()
{
Layers.Sort(l => l.Order);
for (var i = 0; i < Layers.Count; i++)
Layers[i].Order = i;
}
public void DrawLayers(Graphics keyboard, Rect keyboardRect, IDataModel dataModel, bool preview,
bool updateAnimations)
{
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
{
// Setup the DrawingVisual's size
c.PushClip(new RectangleGeometry(keyboardRect));
c.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, keyboardRect);
// Draw the layers
foreach (var layerModel in Layers.OrderByDescending(l => l.Order))
{
layerModel.Update(dataModel, preview, updateAnimations);
layerModel.Draw(dataModel, c, preview, updateAnimations);
}
// Remove the clip
c.Pop();
}
using (var bmp = ImageUtilities.DrawinVisualToBitmap(visual, keyboardRect))
keyboard.DrawImage(bmp, new PointF(0, 0));
}
/// <summary>
/// Gives all the layers and their children in a flat list
/// </summary>
public List<LayerModel> GetLayers()
{
var layers = new List<LayerModel>();
foreach (var layerModel in Layers)
{
layers.Add(layerModel);
layers.AddRange(layerModel.GetLayers());
}
return layers;
}
/// <summary>
/// Generates a flat list containing all layers that must be rendered on the keyboard,
/// the first mouse layer to be rendered and the first headset layer to be rendered
/// </summary>
/// <typeparam name="T">The game data model to base the conditions on</typeparam>
/// <param name="dataModel">Instance of said game data model</param>
/// <param name="includeMice">Whether or not to include mice in the list</param>
/// <param name="includeHeadsets">Whether or not to include headsets in the list</param>
/// <param name="ignoreConditions"></param>
/// <returns>A flat list containing all layers that must be rendered</returns>
public List<LayerModel> GetRenderLayers(IDataModel dataModel, bool includeMice, bool includeHeadsets,
bool ignoreConditions = false)
{
var layers = new List<LayerModel>();
foreach (var layerModel in Layers.OrderByDescending(l => l.Order))
{
if (!layerModel.Enabled || !includeMice && layerModel.LayerType is MouseType ||
!includeHeadsets && layerModel.LayerType is HeadsetType)
continue;
if (!ignoreConditions && !layerModel.ConditionsMet(dataModel))
continue;
layers.Add(layerModel);
layers.AddRange(layerModel.GetRenderLayers(dataModel, includeMice, includeHeadsets, ignoreConditions));
}
return layers;
}
/// <summary>
/// Looks at all the layers wthin the profile and makes sure they are within boundaries of the given rectangle
/// </summary>
/// <param name="keyboardRectangle"></param>
public void FixBoundaries(Rect keyboardRectangle)
{
foreach (var layer in GetLayers())
{
if (!layer.LayerType.MustDraw)
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;
}
}
/// <summary>
/// Draw all the given layers on the given rect
/// </summary>
/// <param name="g">The graphics to draw on</param>
/// <param name="renderLayers">The layers to render</param>
/// <param name="dataModel">The data model to base the layer's properties on</param>
/// <param name="rect">A rectangle matching the current keyboard's size on a scale of 4, used for clipping</param>
/// <param name="preview">Indicates wheter the layer is drawn as a preview, ignoring dynamic properties</param>
/// <param name="updateAnimations">Wheter or not to update the layer's animations</param>
internal void DrawLayers(Graphics g, IEnumerable<LayerModel> renderLayers, IDataModel dataModel, Rect rect,
bool preview, bool updateAnimations)
{
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
{
// Setup the DrawingVisual's size
c.PushClip(new RectangleGeometry(rect));
c.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, rect);
// Draw the layers
foreach (var layerModel in renderLayers)
{
layerModel.Update(dataModel, preview, updateAnimations);
layerModel.Draw(dataModel, c, preview, updateAnimations);
}
// Remove the clip
c.Pop();
}
using (var bmp = ImageUtilities.DrawinVisualToBitmap(visual, rect))
g.DrawImage(bmp, new PointF(0, 0));
}
#region Compare
protected bool Equals(ProfileModel other)
{
return string.Equals(Name, other.Name) &&
string.Equals(KeyboardSlug, other.KeyboardSlug) &&
string.Equals(GameName, other.GameName);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((ProfileModel) obj);
}
public override int GetHashCode()
{
unchecked
{
var hashCode = Name?.GetHashCode() ?? 0;
hashCode = (hashCode*397) ^ (KeyboardSlug?.GetHashCode() ?? 0);
hashCode = (hashCode*397) ^ (GameName?.GetHashCode() ?? 0);
return hashCode;
}
}
#endregion
}
}

View File

@ -1,5 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Artemis.Settings" GeneratedClassName="General">
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)"
GeneratedClassNamespace="Artemis.Settings" GeneratedClassName="General">
<Profiles />
<Settings>
<Setting Name="LastEffect" Type="System.String" Scope="User">

View File

@ -5,7 +5,6 @@ using System.Runtime.InteropServices.ComTypes;
using System.Windows;
using Artemis.Utilities;
using MahApps.Metro;
using NLog;
namespace Artemis.Settings
{

View File

@ -84,7 +84,7 @@
<Track.Thumb>
<Thumb Style="{StaticResource SliderThumbStyle}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"/>
BorderBrush="{TemplateBinding BorderBrush}" />
</Track.Thumb>
</Track>
</ControlTemplate>
@ -491,7 +491,8 @@
SelectedGradient="{Binding}"
Margin="0,0,0,2">
<nc:GradientStopSlider.Background>
<SolidColorBrush Color="{Binding Color}"/>
<SolidColorBrush
Color="{Binding Color}" />
</nc:GradientStopSlider.Background>
</nc:GradientStopSlider>
<ControlTemplate.Triggers>

View File

@ -33,7 +33,7 @@ namespace Artemis.Utilities
{
var colors = new List<byte>();
for (var i = 0; i < 3; i++)
colors.Add((byte)_rand.Next(0, 256));
colors.Add((byte) _rand.Next(0, 256));
var highest = colors.Max();
var lowest = colors.Min();

View File

@ -0,0 +1,43 @@
using System;
using System.Windows.Markup;
using System.Windows.Media;
using System.Xml;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace Artemis.Utilities.Converters
{
/// <summary>
/// Stores a brush by temporarily serializing it to XAML because Json.NET has trouble
/// saving it as JSON
/// </summary>
public class BrushJsonConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
// Turn the brush into an XML node
var doc = new XmlDocument();
doc.LoadXml(XamlWriter.Save(value));
// Serialize the XML node as JSON
var jo = JObject.Parse(JsonConvert.SerializeXmlNode(doc.DocumentElement));
jo.WriteTo(writer);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
JsonSerializer serializer)
{
// Load JObject from stream
var jObject = JObject.Load(reader);
// Seriaze the JSON node to XML
var xml = JsonConvert.DeserializeXmlNode(jObject.ToString());
return XamlReader.Parse(xml.InnerXml);
}
public override bool CanConvert(Type objectType)
{
return typeof(Brush).IsAssignableFrom(objectType);
}
}
}

View File

@ -1,66 +1,79 @@
using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Windows.Data;
using Artemis.Models.Profiles;
using Artemis.Utilities.ParentChild;
namespace Artemis.Utilities
{
/// <summary>
/// Fredrik Hedblad - http://stackoverflow.com/a/3987099/5015269
/// </summary>
public class EnumDescriptionConverter : IValueConverter
{
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var myEnum = (Enum) value;
var description = GetEnumDescription(myEnum);
return description;
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return string.Empty;
}
private string GetEnumDescription(Enum enumObj)
{
var fieldInfo = enumObj.GetType().GetField(enumObj.ToString());
var attribArray = fieldInfo.GetCustomAttributes(false);
if (attribArray.Length == 0)
{
return enumObj.ToString();
}
var attrib = attribArray[0] as DescriptionAttribute;
return attrib?.Description;
}
}
public class LayerOrderConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
IList collection;
if (value is ChildItemCollection<LayerModel, LayerModel>)
collection = ((ChildItemCollection<LayerModel, LayerModel>) value).ToList();
else
collection = (IList) value;
var view = new ListCollectionView(collection);
var sort = new SortDescription(parameter.ToString(), ListSortDirection.Ascending);
view.SortDescriptions.Add(sort);
return view;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Windows.Data;
using Artemis.Profiles.Layers.Models;
using Artemis.Utilities.ParentChild;
namespace Artemis.Utilities.Converters
{
/// <summary>
/// Fredrik Hedblad - http://stackoverflow.com/a/3987099/5015269
/// </summary>
public class EnumDescriptionConverter : IValueConverter
{
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var myEnum = (Enum) value;
var description = GetEnumDescription(myEnum);
return description;
}
object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return string.Empty;
}
private string GetEnumDescription(Enum enumObj)
{
var fieldInfo = enumObj.GetType().GetField(enumObj.ToString());
var attribArray = fieldInfo.GetCustomAttributes(false);
if (attribArray.Length == 0)
{
return enumObj.ToString();
}
var attrib = attribArray[0] as DescriptionAttribute;
return attrib?.Description;
}
}
public class LayerOrderConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
IList collection;
if (value is ChildItemCollection<LayerModel, LayerModel>)
collection = ((ChildItemCollection<LayerModel, LayerModel>) value).ToList();
else
collection = (IList) value;
var view = new ListCollectionView(collection);
var sort = new SortDescription(parameter.ToString(), ListSortDirection.Ascending);
view.SortDescriptions.Add(sort);
return view;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
public class MilliSecondTimespanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? 0.0 : ((TimeSpan)value).TotalMilliseconds;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return value == null ? new TimeSpan() : TimeSpan.FromMilliseconds((double)value);
}
}
}

View File

@ -4,6 +4,7 @@ using System.IO.MemoryMappedFiles;
using System.Linq;
using System.Text;
using System.Windows.Media;
using Ninject.Extensions.Logging;
namespace Artemis.Utilities.DataReaders
{
@ -12,10 +13,11 @@ namespace Artemis.Utilities.DataReaders
/// </summary>
public class MmfReader
{
private DateTime _lastFailure;
private readonly ILogger _logger;
public MmfReader(string mmfName)
public MmfReader(string mmfName, ILogger logger)
{
_logger = logger;
MmfName = mmfName;
}
@ -54,8 +56,9 @@ namespace Artemis.Utilities.DataReaders
}
return colors;
}
catch (FormatException)
catch (FormatException e)
{
_logger.Trace(e, "Failed to parse to color array");
return null;
}
}
@ -67,10 +70,6 @@ namespace Artemis.Utilities.DataReaders
/// <returns></returns>
private string ReadMmf(string fileName)
{
// Don't read the file within one second after failing
//if (DateTime.Now - _lastFailure > new TimeSpan(0, 0, 1))
// return null;
try
{
using (var mmf = MemoryMappedFile.OpenExisting(fileName))
@ -85,9 +84,9 @@ namespace Artemis.Utilities.DataReaders
}
}
}
catch (FileNotFoundException)
catch (FileNotFoundException e)
{
_lastFailure = DateTime.Now;
_logger.Trace(e, "Failed to read mff");
return null;
//ignored
}

View File

@ -5,8 +5,8 @@ using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Windows;
using System.Xml.Serialization;
using Microsoft.Win32;
using Newtonsoft.Json;
using static System.String;
namespace Artemis.Utilities
@ -39,7 +39,7 @@ namespace Artemis.Utilities
}
/// <summary>
/// Perform a deep Copy of the object.
/// Perform a deep Copy of the object, using Json as a serialisation method.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
@ -50,35 +50,20 @@ namespace Artemis.Utilities
if (ReferenceEquals(source, null))
return default(T);
var serializer = new XmlSerializer(typeof(T));
Stream stream = new MemoryStream();
using (stream)
var deserializeSettings = new JsonSerializerSettings
{
serializer.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T) serializer.Deserialize(stream);
}
}
public static string Serialize<T>(T source)
{
// Don't serialize a null object, simply return the default for that object
if (ReferenceEquals(source, null))
return null;
var serializer = new XmlSerializer(typeof(T));
var stream = new StringWriter();
using (stream)
{
serializer.Serialize(stream, source);
return stream.ToString();
}
ObjectCreationHandling = ObjectCreationHandling.Replace,
TypeNameHandling = TypeNameHandling.Auto
};
return (T)JsonConvert.DeserializeObject(JsonConvert.SerializeObject(source), source.GetType(),
deserializeSettings);
}
public static object GetPropertyValue(object o, string path)
{
var propertyNames = path.Split('.');
var value = o.GetType().GetProperty(propertyNames[0]).GetValue(o, null);
var prop = o.GetType().GetProperty(propertyNames[0]);
var value = prop.GetValue(o, null);
if (propertyNames.Length == 1 || value == null)
return value;

View File

@ -8,9 +8,7 @@ namespace Artemis.Utilities
{
private readonly int _delay;
private readonly FrameDimension _dimension;
private readonly int _frameCount;
private readonly Image _gifImage;
private int _currentFrame = -1;
private DateTime _lastRequest;
private int _step = 1;
@ -19,7 +17,7 @@ namespace Artemis.Utilities
_lastRequest = DateTime.Now;
_gifImage = Image.FromFile(path); //initialize
_dimension = new FrameDimension(_gifImage.FrameDimensionsList[0]); //gets the GUID
_frameCount = _gifImage.GetFrameCount(_dimension); //total frames in the animation
FrameCount = _gifImage.GetFrameCount(_dimension); //total frames in the animation
Source = path;
@ -27,7 +25,20 @@ namespace Artemis.Utilities
_delay = (item.Value[0] + item.Value[1]*256)*10; // Time is in 1/100th of a second
}
public string Source { get; set; }
/// <summary>
/// Gets the path the GifImage is based on
/// </summary>
public string Source { get; private set; }
/// <summary>
/// Gets or sets the current frame, set to -1 to reset
/// </summary>
public int CurrentFrame { get; set; } = -1;
/// <summary>
/// Gets the total amount of frames in the GIF
/// </summary>
public int FrameCount { get; }
/// <summary>
/// Whether the gif should play backwards when it reaches the end
@ -39,23 +50,23 @@ namespace Artemis.Utilities
// Only pass the next frame if the proper amount of time has passed
if ((DateTime.Now - _lastRequest).Milliseconds > _delay)
{
_currentFrame += _step;
CurrentFrame += _step;
_lastRequest = DateTime.Now;
}
//if the animation reaches a boundary...
if (_currentFrame < _frameCount && _currentFrame >= 1)
return GetFrame(_currentFrame);
if (CurrentFrame < FrameCount && CurrentFrame >= 1)
return GetFrame(CurrentFrame);
if (ReverseAtEnd)
{
_step *= -1; //...reverse the count
_currentFrame += _step; //apply it
CurrentFrame += _step; //apply it
}
else
_currentFrame = 0; //...or start over
CurrentFrame = 0; //...or start over
return GetFrame(_currentFrame);
return GetFrame(CurrentFrame);
}
public Image GetFrame(int index)

View File

@ -70,5 +70,24 @@ namespace Artemis.Utilities
}
return bitmap;
}
/// <summary>
/// Loads the BowIcon from resources and colors it according to the current theme
/// </summary>
/// <returns></returns>
public static RenderTargetBitmap GenerateWindowIcon()
{
var iconImage = new System.Windows.Controls.Image
{
Source = (DrawingImage) Application.Current.MainWindow.Resources["BowIcon"],
Stretch = Stretch.Uniform,
Margin = new Thickness(20)
};
iconImage.Arrange(new Rect(0, 0, 100, 100));
var bitmap = new RenderTargetBitmap(100, 100, 96, 96, PixelFormats.Pbgra32);
bitmap.Render(iconImage);
return bitmap;
}
}
}

View File

@ -1,46 +0,0 @@
using Artemis.Models.Profiles.Properties;
namespace Artemis.Utilities.Layers
{
public static class AnimationUpdater
{
public static void UpdateAnimation(KeyboardPropertiesModel properties, bool updateAnimations)
{
const int scale = 4;
var progress = properties.AnimationProgress;
switch (properties.Animation)
{
case LayerAnimation.SlideRight:
case LayerAnimation.SlideLeft:
if (progress + properties.AnimationSpeed * 2 >= properties.Width*scale)
progress = 0;
progress = progress + properties.AnimationSpeed*2;
break;
case LayerAnimation.SlideDown:
case LayerAnimation.SlideUp:
if (progress + properties.AnimationSpeed * 2 >= properties.Height*scale)
progress = 0;
progress = progress + properties.AnimationSpeed*2;
break;
case LayerAnimation.Pulse:
if (progress > 2)
progress = 0;
progress = progress + properties.AnimationSpeed/2;
break;
case LayerAnimation.Grow:
if (progress > 10)
progress = 0;
progress = progress + properties.AnimationSpeed/2.5;
break;
default:
progress = progress + properties.AnimationSpeed*2;
break;
}
// If not previewing, store the animation progress in the actual model for the next frame
if (updateAnimations)
properties.AnimationProgress = progress;
}
}
}

View File

@ -1,161 +0,0 @@
using System;
using System.Drawing;
using System.IO;
using System.Windows;
using System.Windows.Media;
using Artemis.Models.Profiles;
using Artemis.Models.Profiles.Properties;
using Artemis.Properties;
using Pen = System.Windows.Media.Pen;
using Point = System.Windows.Point;
using Size = System.Windows.Size;
namespace Artemis.Utilities.Layers
{
public static class Drawer
{
public static void Draw(DrawingContext c, KeyboardPropertiesModel props, AppliedProperties applied)
{
if (applied.Brush == null)
return;
const int scale = 4;
// Set up variables for this frame
var rect = props.Contain
? new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale, applied.Height*scale)
: new Rect(props.X*scale, props.Y*scale, props.Width*scale, props.Height*scale);
var s1 = new Rect();
var s2 = new Rect();
if (props.Animation == LayerAnimation.SlideRight)
{
s1 = new Rect(new Point(rect.X + props.AnimationProgress, rect.Y), new Size(rect.Width, rect.Height));
s2 = new Rect(new Point(s1.X - rect.Width, rect.Y), new Size(rect.Width + 1, rect.Height));
}
if (props.Animation == LayerAnimation.SlideLeft)
{
s1 = new Rect(new Point(rect.X - props.AnimationProgress, rect.Y),
new Size(rect.Width + 0.05, rect.Height));
s2 = new Rect(new Point(s1.X + rect.Width, rect.Y), new Size(rect.Width, rect.Height));
}
if (props.Animation == LayerAnimation.SlideDown)
{
s1 = new Rect(new Point(rect.X, rect.Y + props.AnimationProgress), new Size(rect.Width, rect.Height));
s2 = new Rect(new Point(s1.X, s1.Y - rect.Height), new Size(rect.Width, rect.Height));
}
if (props.Animation == LayerAnimation.SlideUp)
{
s1 = new Rect(new Point(rect.X, rect.Y - props.AnimationProgress), new Size(rect.Width, rect.Height));
s2 = new Rect(new Point(s1.X, s1.Y + rect.Height), new Size(rect.Width, rect.Height));
}
var clip = new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale, applied.Height*scale);
DrawRectangle(c, props, applied, clip, rect, s1, s2);
}
private static void DrawRectangle(DrawingContext c, KeyboardPropertiesModel props, AppliedProperties applied,
Rect clip, Rect rectangle, Rect slide1, Rect slide2)
{
// Apply the pulse animation
if (props.Animation == LayerAnimation.Pulse)
applied.Brush.Opacity = (Math.Sin(props.AnimationProgress*Math.PI) + 1)*(props.Opacity/2);
else
applied.Brush.Opacity = props.Opacity;
if (props.Animation == LayerAnimation.Grow)
{
// Take an offset of 4 to allow layers to slightly leave their bounds
var progress = (6.0 - props.AnimationProgress)*10.0;
if (progress < 0)
{
applied.Brush.Opacity = 1 + 0.025*progress;
if (applied.Brush.Opacity < 0)
applied.Brush.Opacity = 0;
if (applied.Brush.Opacity > 1)
applied.Brush.Opacity = 1;
}
rectangle.Inflate(-rectangle.Width/100.0*progress, -rectangle.Height/100.0*progress);
clip.Inflate(-clip.Width/100.0*progress, -clip.Height/100.0*progress);
}
c.PushClip(new RectangleGeometry(clip));
// Most animation types can be drawn regularly
if (props.Animation == LayerAnimation.None ||
props.Animation == LayerAnimation.Grow ||
props.Animation == LayerAnimation.Pulse)
{
c.DrawRectangle(applied.Brush, null, rectangle);
}
// Sliding animations however, require offsetting two rects
else
{
c.PushClip(new RectangleGeometry(clip));
c.DrawRectangle(applied.Brush, null, slide1);
c.DrawRectangle(applied.Brush, null, slide2);
c.Pop();
}
c.Pop();
}
public static GifImage DrawGif(DrawingContext c, KeyboardPropertiesModel props, AppliedProperties applied,
GifImage gifImage)
{
if (string.IsNullOrEmpty(props.GifFile))
return null;
if (!File.Exists(props.GifFile))
return null;
const int scale = 4;
// Only reconstruct GifImage if the underlying source has changed
if (gifImage == null)
gifImage = new GifImage(props.GifFile);
if (gifImage.Source != props.GifFile)
gifImage = new GifImage(props.GifFile);
var gifRect = new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale,
applied.Height*scale);
lock (gifImage)
{
var draw = gifImage.GetNextFrame();
c.DrawImage(ImageUtilities.BitmapToBitmapImage(new Bitmap(draw)), gifRect);
}
return gifImage;
}
public static void UpdateMouse(LayerPropertiesModel properties)
{
}
public static void UpdateHeadset(LayerPropertiesModel properties)
{
}
public static ImageSource DrawThumbnail(LayerModel layerModel)
{
var thumbnailRect = new Rect(0, 0, 18, 18);
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
{
// Draw the appropiate icon or draw the brush
if (layerModel.LayerType == LayerType.Folder)
c.DrawImage(ImageUtilities.BitmapToBitmapImage(Resources.folder), thumbnailRect);
else if (layerModel.LayerType == LayerType.Headset)
c.DrawImage(ImageUtilities.BitmapToBitmapImage(Resources.headset), thumbnailRect);
else if (layerModel.LayerType == LayerType.Mouse)
c.DrawImage(ImageUtilities.BitmapToBitmapImage(Resources.mouse), thumbnailRect);
else if (layerModel.LayerType == LayerType.KeyboardGif)
c.DrawImage(ImageUtilities.BitmapToBitmapImage(Resources.gif), thumbnailRect);
else if (layerModel.LayerType == LayerType.Keyboard && layerModel.Properties.Brush != null)
c.DrawRectangle(layerModel.Properties.Brush, new Pen(new SolidColorBrush(Colors.White), 1),
thumbnailRect);
}
var image = new DrawingImage(visual.Drawing);
return image;
}
}
}

View File

@ -48,14 +48,14 @@ namespace Artemis.Utilities
{
if (_waitTime < _stickyTime)
{
Thread.Sleep(100);
Thread.Sleep(10);
continue;
}
while (_waitTime > 0)
{
Thread.Sleep(50);
_waitTime -= 50;
Thread.Sleep(10);
_waitTime -= 10;
}
_value = _toStick;
}

View File

@ -0,0 +1,58 @@
using System.Windows;
using System.Windows.Media;
using Artemis.Events;
using Caliburn.Micro;
namespace Artemis.ViewModels
{
public class DebugViewModel : Screen, IHandle<RazerColorArrayChanged>
{
private readonly IEventAggregator _events;
private DrawingImage _razerDisplay;
public DebugViewModel(IEventAggregator events)
{
_events = events;
}
public DrawingImage RazerDisplay
{
get { return _razerDisplay; }
set
{
if (Equals(value, _razerDisplay)) return;
_razerDisplay = value;
NotifyOfPropertyChange(() => RazerDisplay);
}
}
public void Handle(RazerColorArrayChanged message)
{
var visual = new DrawingVisual();
using (var dc = visual.RenderOpen())
{
dc.PushClip(new RectangleGeometry(new Rect(0, 0, 22, 6)));
for (var y = 0; y < 6; y++)
{
for (var x = 0; x < 22; x++)
dc.DrawRectangle(new SolidColorBrush(message.Colors[y, x]), null, new Rect(x, y, 1, 1));
}
}
var drawnDisplay = new DrawingImage(visual.Drawing);
drawnDisplay.Freeze();
RazerDisplay = drawnDisplay;
}
protected override void OnActivate()
{
_events.Subscribe(this);
base.OnActivate();
}
protected override void OnDeactivate(bool close)
{
_events.Unsubscribe(this);
base.OnDeactivate(close);
}
}
}

View File

@ -1,9 +1,11 @@
using System.ComponentModel;
using System.Diagnostics;
using System.Dynamic;
using System.Linq;
using Artemis.Events;
using Artemis.Managers;
using Artemis.Settings;
using Artemis.Utilities;
using Caliburn.Micro;
using MahApps.Metro.Controls;
using NLog;
@ -14,15 +16,18 @@ namespace Artemis.ViewModels.Flyouts
public sealed class FlyoutSettingsViewModel : FlyoutBaseViewModel, IHandle<ToggleEnabled>,
IHandle<ActiveEffectChanged>
{
private readonly DebugViewModel _debugViewModel;
private readonly ILogger _logger;
private string _activeEffectName;
private bool _enableDebug;
private GeneralSettings _generalSettings;
private string _selectedKeyboardProvider;
public FlyoutSettingsViewModel(MainManager mainManager, IEventAggregator events, ILogger logger)
public FlyoutSettingsViewModel(MainManager mainManager, IEventAggregator events, ILogger logger,
DebugViewModel debugViewModel)
{
_logger = logger;
_debugViewModel = debugViewModel;
MainManager = mainManager;
Header = "Settings";
@ -178,6 +183,18 @@ namespace Artemis.ViewModels.Flyouts
MainManager.EnableProgram();
}
public void ShowDebug()
{
IWindowManager manager = new WindowManager();
dynamic settings = new ExpandoObject();
var icon = ImageUtilities.GenerateWindowIcon();
settings.Title = "Artemis | Debugger";
settings.Icon = icon;
manager.ShowWindow(_debugViewModel, null, settings);
}
public void ResetSettings()
{
GeneralSettings.ResetSettings();

View File

@ -0,0 +1,42 @@
using System;
using Artemis.Profiles.Layers.Models;
using Artemis.Utilities;
using Caliburn.Micro;
namespace Artemis.ViewModels.Profiles.Events
{
public class EventPropertiesViewModel : PropertyChangedBase
{
private EventPropertiesModel _proposedProperties;
public EventPropertiesViewModel(EventPropertiesModel eventPropertiesModel)
{
if (eventPropertiesModel == null)
ProposedProperties = new KeyboardEventPropertiesModel
{
ExpirationType = ExpirationType.Time,
Length = new TimeSpan(0, 0, 1),
TriggerDelay = new TimeSpan(0)
};
else
ProposedProperties = GeneralHelpers.Clone(eventPropertiesModel);
}
public EventPropertiesModel ProposedProperties
{
get { return _proposedProperties; }
set
{
if (Equals(value, _proposedProperties)) return;
_proposedProperties = value;
NotifyOfPropertyChange(() => ProposedProperties);
}
}
public EventPropertiesModel GetAppliedProperties()
{
return GeneralHelpers.Clone(ProposedProperties);
}
}
}

View File

@ -1,6 +1,6 @@
using System.ComponentModel;
using System.Linq;
using Artemis.Models.Profiles;
using Artemis.Profiles.Layers.Models;
using Artemis.Utilities;
using Caliburn.Micro;

View File

@ -1,10 +1,11 @@
using System.ComponentModel;
using System.Linq;
using Artemis.Models.Profiles.Properties;
using Artemis.Profiles.Layers.Models;
using Artemis.Utilities;
using Caliburn.Micro;
using Castle.Core.Internal;
namespace Artemis.ViewModels.Profiles
{
public sealed class LayerDynamicPropertiesViewModel : PropertyChangedBase
@ -21,13 +22,13 @@ namespace Artemis.ViewModels.Profiles
public LayerDynamicPropertiesViewModel(string property,
BindableCollection<GeneralHelpers.PropertyCollection> dataModelProps,
KeyboardPropertiesModel keyboardProperties)
LayerPropertiesModel layerPropertiesModel)
{
_property = property;
// Look for the existing property model
Proposed = new DynamicPropertiesModel();
var original = keyboardProperties.DynamicProperties.FirstOrDefault(lp => lp.LayerProperty == _property);
var original = layerPropertiesModel.DynamicProperties.FirstOrDefault(lp => lp.LayerProperty == _property);
if (original == null)
{
Proposed.LayerProperty = property;
@ -161,22 +162,22 @@ namespace Artemis.ViewModels.Profiles
case "Width":
LayerPropertyOptions = new BindableCollection<LayerPropertyOptions>
{
Models.Profiles.Properties.LayerPropertyOptions.LeftToRight,
Models.Profiles.Properties.LayerPropertyOptions.RightToLeft
Artemis.Profiles.Layers.Models.LayerPropertyOptions.LeftToRight,
Artemis.Profiles.Layers.Models.LayerPropertyOptions.RightToLeft
};
break;
case "Height":
LayerPropertyOptions = new BindableCollection<LayerPropertyOptions>
{
Models.Profiles.Properties.LayerPropertyOptions.Downwards,
Models.Profiles.Properties.LayerPropertyOptions.Upwards
Artemis.Profiles.Layers.Models.LayerPropertyOptions.Downwards,
Artemis.Profiles.Layers.Models.LayerPropertyOptions.Upwards
};
break;
case "Opacity":
LayerPropertyOptions = new BindableCollection<LayerPropertyOptions>
{
Models.Profiles.Properties.LayerPropertyOptions.Increase,
Models.Profiles.Properties.LayerPropertyOptions.Decrease
Artemis.Profiles.Layers.Models.LayerPropertyOptions.Increase,
Artemis.Profiles.Layers.Models.LayerPropertyOptions.Decrease
};
break;
}
@ -206,14 +207,14 @@ namespace Artemis.ViewModels.Profiles
}
}
public void Apply(KeyboardPropertiesModel keyboardProperties)
public void Apply(LayerModel layerModel)
{
var original = keyboardProperties.DynamicProperties.FirstOrDefault(lp => lp.LayerProperty == _property);
var original = layerModel.Properties.DynamicProperties.FirstOrDefault(lp => lp.LayerProperty == _property);
if (original != null)
keyboardProperties.DynamicProperties.Remove(original);
layerModel.Properties.DynamicProperties.Remove(original);
if (!Proposed.GameProperty.IsNullOrEmpty())
keyboardProperties.DynamicProperties.Add(Proposed);
layerModel.Properties.DynamicProperties.Add(Proposed);
}
}
}

View File

@ -1,14 +1,20 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles;
using Artemis.Models.Profiles.Properties;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
using Artemis.Profiles.Layers.Types.Keyboard;
using Artemis.Profiles.Layers.Types.KeyboardGif;
using Artemis.Services;
using Artemis.Utilities;
using Artemis.ViewModels.Profiles.Properties;
using Artemis.ViewModels.Profiles.Events;
using Artemis.ViewModels.Profiles.Layers;
using Caliburn.Micro;
using Newtonsoft.Json;
using Ninject;
namespace Artemis.ViewModels.Profiles
@ -16,15 +22,18 @@ namespace Artemis.ViewModels.Profiles
public sealed class LayerEditorViewModel : Screen
{
private readonly IDataModel _dataModel;
private readonly List<ILayerAnimation> _layerAnimations;
private EventPropertiesViewModel _eventPropertiesViewModel;
private LayerModel _layer;
private LayerPropertiesViewModel _layerPropertiesViewModel;
private LayerType _layerType;
private LayerModel _proposedLayer;
private LayerPropertiesModel _proposedProperties;
private ILayerType _selectedLayerType;
public LayerEditorViewModel(IDataModel dataModel, LayerModel layer)
public LayerEditorViewModel(IDataModel dataModel, LayerModel layer, IEnumerable<ILayerType> layerTypes,
List<ILayerAnimation> layerAnimations)
{
_dataModel = dataModel;
_layerAnimations = layerAnimations;
Layer = layer;
ProposedLayer = GeneralHelpers.Clone(layer);
@ -32,26 +41,28 @@ namespace Artemis.ViewModels.Profiles
if (Layer.Properties == null)
Layer.SetupProperties();
DataModelProps = new BindableCollection<GeneralHelpers.PropertyCollection>();
DataModelProps.AddRange(GeneralHelpers.GenerateTypeMap(dataModel));
LayerConditionVms = new BindableCollection<LayerConditionViewModel>(layer.Properties.Conditions
.Select(c => new LayerConditionViewModel(this, c, DataModelProps)));
LayerTypes = new BindableCollection<ILayerType>(layerTypes);
DataModelProps = new BindableCollection<GeneralHelpers.PropertyCollection>(
GeneralHelpers.GenerateTypeMap(dataModel));
LayerConditionVms = new BindableCollection<LayerConditionViewModel>(
layer.Properties.Conditions.Select(c => new LayerConditionViewModel(this, c, DataModelProps)));
PropertyChanged += PropertiesViewModelHandler;
PreSelect();
}
public bool ModelChanged { get; set; }
[Inject]
public MetroDialogService DialogService { get; set; }
public BindableCollection<ILayerType> LayerTypes { get; set; }
public BindableCollection<GeneralHelpers.PropertyCollection> DataModelProps { get; set; }
public BindableCollection<string> LayerTypes => new BindableCollection<string>();
public BindableCollection<LayerConditionViewModel> LayerConditionVms { get; set; }
public bool KeyboardGridIsVisible => ProposedLayer.LayerType is KeyboardType;
public bool GifGridIsVisible => ProposedLayer.LayerType is KeyboardGifType;
public LayerModel Layer
{
@ -75,17 +86,6 @@ namespace Artemis.ViewModels.Profiles
}
}
public LayerType LayerType
{
get { return _layerType; }
set
{
if (value == _layerType) return;
_layerType = value;
NotifyOfPropertyChange(() => LayerType);
}
}
public LayerPropertiesViewModel LayerPropertiesViewModel
{
get { return _layerPropertiesViewModel; }
@ -97,59 +97,66 @@ namespace Artemis.ViewModels.Profiles
}
}
public bool KeyboardGridIsVisible => ProposedLayer.LayerType == LayerType.Keyboard;
public bool GifGridIsVisible => ProposedLayer.LayerType == LayerType.KeyboardGif;
public EventPropertiesViewModel EventPropertiesViewModel
{
get { return _eventPropertiesViewModel; }
set
{
if (Equals(value, _eventPropertiesViewModel)) return;
_eventPropertiesViewModel = value;
NotifyOfPropertyChange(() => EventPropertiesViewModel);
}
}
public ILayerType SelectedLayerType
{
get { return _selectedLayerType; }
set
{
if (Equals(value, _selectedLayerType)) return;
_selectedLayerType = value;
NotifyOfPropertyChange(() => SelectedLayerType);
}
}
public void PreSelect()
{
LayerType = ProposedLayer.LayerType;
if (LayerType == LayerType.Folder && !(LayerPropertiesViewModel is FolderPropertiesViewModel))
LayerPropertiesViewModel = new FolderPropertiesViewModel(_dataModel, ProposedLayer.Properties);
SelectedLayerType = LayerTypes.FirstOrDefault(t => t.Name == ProposedLayer.LayerType.Name);
ToggleIsEvent();
}
private void PropertiesViewModelHandler(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName != "LayerType")
if (e.PropertyName != "SelectedLayerType")
return;
// Store the brush in case the user wants to reuse it
var oldBrush = LayerPropertiesViewModel?.GetAppliedProperties().Brush;
var oldBrush = ProposedLayer.Properties.Brush;
// Update the model
if (ProposedLayer.LayerType != LayerType)
if (ProposedLayer.LayerType.GetType() != SelectedLayerType.GetType())
{
ProposedLayer.LayerType = LayerType;
ProposedLayer.LayerType = SelectedLayerType;
ProposedLayer.SetupProperties();
}
// Let the layer type handle the viewmodel setup
LayerPropertiesViewModel = ProposedLayer.LayerType.SetupViewModel(LayerPropertiesViewModel, _layerAnimations,
_dataModel, ProposedLayer);
if (oldBrush != null)
ProposedLayer.Properties.Brush = oldBrush;
// Update the KeyboardPropertiesViewModel if it's being used
var model = LayerPropertiesViewModel as KeyboardPropertiesViewModel;
if (model != null)
model.IsGif = LayerType == LayerType.KeyboardGif;
// Apply the proper PropertiesViewModel
if ((LayerType == LayerType.Keyboard || LayerType == LayerType.KeyboardGif) &&
!(LayerPropertiesViewModel is KeyboardPropertiesViewModel))
{
LayerPropertiesViewModel = new KeyboardPropertiesViewModel(_dataModel, ProposedLayer.Properties)
{
IsGif = LayerType == LayerType.KeyboardGif
};
}
else if (LayerType == LayerType.Mouse && !(LayerPropertiesViewModel is MousePropertiesViewModel))
LayerPropertiesViewModel = new MousePropertiesViewModel(_dataModel, ProposedLayer.Properties);
else if (LayerType == LayerType.Headset && !(LayerPropertiesViewModel is HeadsetPropertiesViewModel))
LayerPropertiesViewModel = new HeadsetPropertiesViewModel(_dataModel, ProposedLayer.Properties);
else if (LayerType == LayerType.Folder && !(LayerPropertiesViewModel is FolderPropertiesViewModel))
LayerPropertiesViewModel = new FolderPropertiesViewModel(_dataModel, ProposedLayer.Properties);
NotifyOfPropertyChange(() => LayerPropertiesViewModel);
}
public void ToggleIsEvent()
{
EventPropertiesViewModel = ProposedLayer.IsEvent
? new EventPropertiesViewModel(Layer.EventProperties)
: null;
}
public void AddCondition()
{
var condition = new LayerConditionModel();
@ -158,19 +165,20 @@ namespace Artemis.ViewModels.Profiles
public void Apply()
{
Layer.Name = ProposedLayer.Name;
Layer.LayerType = ProposedLayer.LayerType;
LayerPropertiesViewModel?.ApplyProperties();
Layer = GeneralHelpers.Clone(ProposedLayer);
// TODO: EventPropVM must have layer too
if (EventPropertiesViewModel != null)
Layer.EventProperties = EventPropertiesViewModel.GetAppliedProperties();
if (LayerPropertiesViewModel != null)
Layer.Properties = LayerPropertiesViewModel.GetAppliedProperties();
Layer.Properties.Conditions.Clear();
foreach (var conditionViewModel in LayerConditionVms)
{
Layer.Properties.Conditions.Add(conditionViewModel.LayerConditionModel);
}
if (Layer.LayerType != LayerType.KeyboardGif)
return; // Don't bother checking for a GIF path unless the type is GIF
// Don't bother checking for a GIF path unless the type is GIF
if (!(Layer.LayerType is KeyboardGifType))
return;
if (!File.Exists(((KeyboardPropertiesModel) Layer.Properties).GifFile))
DialogService.ShowErrorMessageBox("Couldn't find or access the provided GIF file.");
}
@ -185,25 +193,26 @@ namespace Artemis.ViewModels.Profiles
public override async void CanClose(Action<bool> callback)
{
// Create a fake layer and apply the properties to it
var fakeLayer = GeneralHelpers.Clone(ProposedLayer);
if (LayerPropertiesViewModel != null)
fakeLayer.Properties = LayerPropertiesViewModel.GetAppliedProperties();
fakeLayer.Properties.Conditions.Clear();
LayerPropertiesViewModel?.ApplyProperties();
// TODO: EventPropVM must have layer too
if (EventPropertiesViewModel != null)
ProposedLayer.EventProperties = EventPropertiesViewModel.GetAppliedProperties();
ProposedLayer.Properties.Conditions.Clear();
foreach (var conditionViewModel in LayerConditionVms)
fakeLayer.Properties.Conditions.Add(conditionViewModel.LayerConditionModel);
ProposedLayer.Properties.Conditions.Add(conditionViewModel.LayerConditionModel);
var fake = GeneralHelpers.Serialize(fakeLayer);
var real = GeneralHelpers.Serialize(Layer);
var current = JsonConvert.SerializeObject(Layer, Formatting.Indented);
var proposed = JsonConvert.SerializeObject(ProposedLayer, Formatting.Indented);
if (fake.Equals(real))
if (current.Equals(proposed))
{
callback(true);
return;
}
var close =
await DialogService.ShowQuestionMessageBox("Unsaved changes", "Do you want to discard your changes?");
var close = await DialogService
.ShowQuestionMessageBox("Unsaved changes", "Do you want to discard your changes?");
callback(close.Value);
}
}

View File

@ -0,0 +1,16 @@
using Artemis.Models.Interfaces;
using Artemis.Profiles.Layers.Models;
namespace Artemis.ViewModels.Profiles.Layers
{
public class FolderPropertiesViewModel : LayerPropertiesViewModel
{
public FolderPropertiesViewModel(LayerModel layerModel, IDataModel dataModel) : base(layerModel, dataModel)
{
}
public override void ApplyProperties()
{
}
}
}

View File

@ -0,0 +1,44 @@
using System.Collections.Generic;
using Artemis.Models.Interfaces;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
using Artemis.Utilities;
using Caliburn.Micro;
namespace Artemis.ViewModels.Profiles.Layers
{
public class HeadsetPropertiesViewModel : LayerPropertiesViewModel
{
private ILayerAnimation _selectedLayerAnimation;
public HeadsetPropertiesViewModel(LayerModel layerModel, IDataModel dataModel,
IEnumerable<ILayerAnimation> layerAnimations) : base(layerModel, dataModel)
{
LayerAnimations = new BindableCollection<ILayerAnimation>(layerAnimations);
OpacityProperties = new LayerDynamicPropertiesViewModel("Opacity",
new BindableCollection<GeneralHelpers.PropertyCollection>(GeneralHelpers.GenerateTypeMap(dataModel)),
layerModel.Properties);
}
public BindableCollection<ILayerAnimation> LayerAnimations { get; set; }
public LayerDynamicPropertiesViewModel OpacityProperties { get; set; }
public ILayerAnimation SelectedLayerAnimation
{
get { return _selectedLayerAnimation; }
set
{
if (Equals(value, _selectedLayerAnimation)) return;
_selectedLayerAnimation = value;
NotifyOfPropertyChange(() => SelectedLayerAnimation);
}
}
public override void ApplyProperties()
{
OpacityProperties.Apply(LayerModel);
LayerModel.Properties.Brush = Brush;
LayerModel.LayerAnimation = SelectedLayerAnimation;
}
}
}

View File

@ -0,0 +1,83 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Artemis.Models.Interfaces;
using Artemis.Profiles.Layers.Interfaces;
using Artemis.Profiles.Layers.Models;
using Artemis.Profiles.Layers.Types.Keyboard;
using Caliburn.Micro;
using static Artemis.Utilities.GeneralHelpers;
namespace Artemis.ViewModels.Profiles.Layers
{
public class KeyboardPropertiesViewModel : LayerPropertiesViewModel
{
private bool _isGif;
private ILayerAnimation _selectedLayerAnimation;
public KeyboardPropertiesViewModel(LayerModel layerModel, IDataModel dataModel,
IEnumerable<ILayerAnimation> layerAnimations) : base(layerModel, dataModel)
{
LayerAnimations = new BindableCollection<ILayerAnimation>(layerAnimations);
var dataModelProps = new BindableCollection<PropertyCollection>(GenerateTypeMap(dataModel));
HeightProperties = new LayerDynamicPropertiesViewModel("Height", dataModelProps, layerModel.Properties);
WidthProperties = new LayerDynamicPropertiesViewModel("Width", dataModelProps, layerModel.Properties);
OpacityProperties = new LayerDynamicPropertiesViewModel("Opacity", dataModelProps, layerModel.Properties);
SelectedLayerAnimation = LayerAnimations.FirstOrDefault(l => l.Name == layerModel.LayerAnimation?.Name) ??
LayerAnimations.First(l => l.Name == "None");
}
public bool ShowGif => IsGif;
public bool ShowBrush => !IsGif;
public BindableCollection<PropertyCollection> DataModelProps { get; set; }
public BindableCollection<ILayerAnimation> LayerAnimations { get; set; }
public LayerDynamicPropertiesViewModel HeightProperties { get; set; }
public LayerDynamicPropertiesViewModel WidthProperties { get; set; }
public LayerDynamicPropertiesViewModel OpacityProperties { get; set; }
public bool IsGif
{
get { return _isGif; }
set
{
_isGif = value;
NotifyOfPropertyChange(() => ShowGif);
NotifyOfPropertyChange(() => ShowBrush);
}
}
public ILayerAnimation SelectedLayerAnimation
{
get { return _selectedLayerAnimation; }
set
{
if (Equals(value, _selectedLayerAnimation)) return;
_selectedLayerAnimation = value;
NotifyOfPropertyChange(() => SelectedLayerAnimation);
}
}
public void BrowseGif()
{
var dialog = new OpenFileDialog {Filter = "Animated image file (*.gif)|*.gif"};
var result = dialog.ShowDialog();
if (result != DialogResult.OK)
return;
((KeyboardPropertiesModel) LayerModel.Properties).GifFile = dialog.FileName;
NotifyOfPropertyChange(() => LayerModel);
}
public override void ApplyProperties()
{
HeightProperties.Apply(LayerModel);
WidthProperties.Apply(LayerModel);
OpacityProperties.Apply(LayerModel);
LayerModel.Properties.Brush = Brush;
LayerModel.LayerAnimation = SelectedLayerAnimation;
}
}
}

Some files were not shown because too many files have changed in this diff Show More