diff --git a/Artemis/Artemis.sln b/Artemis/Artemis.sln index 0e9c57ea1..9e2a09e30 100644 --- a/Artemis/Artemis.sln +++ b/Artemis/Artemis.sln @@ -9,6 +9,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Razer2Artemis", "Razer2Arte EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "UnrealTournament2Artemis", "UnrealTournament2Artemis\UnrealTournament2Artemis.vcxproj", "{3541864F-1662-4BD6-8328-2C87AE61D152}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColorBox", "ColorBox\ColorBox.csproj", "{40085232-ACED-4CBE-945B-90BA8153C151}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution CD_ROM|Any CPU = CD_ROM|Any CPU @@ -114,6 +116,36 @@ Global {3541864F-1662-4BD6-8328-2C87AE61D152}.SingleImage|x64.Build.0 = Release|x64 {3541864F-1662-4BD6-8328-2C87AE61D152}.SingleImage|x86.ActiveCfg = Release|Win32 {3541864F-1662-4BD6-8328-2C87AE61D152}.SingleImage|x86.Build.0 = Release|Win32 + {40085232-ACED-4CBE-945B-90BA8153C151}.CD_ROM|Any CPU.ActiveCfg = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.CD_ROM|Any CPU.Build.0 = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.CD_ROM|x64.ActiveCfg = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.CD_ROM|x64.Build.0 = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.CD_ROM|x86.ActiveCfg = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.CD_ROM|x86.Build.0 = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.Debug|Any CPU.Build.0 = Debug|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.Debug|x64.ActiveCfg = Debug|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.Debug|x64.Build.0 = Debug|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.Debug|x86.ActiveCfg = Debug|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.Debug|x86.Build.0 = Debug|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.DVD-5|Any CPU.ActiveCfg = Debug|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.DVD-5|Any CPU.Build.0 = Debug|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.DVD-5|x64.ActiveCfg = Debug|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.DVD-5|x64.Build.0 = Debug|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.DVD-5|x86.ActiveCfg = Debug|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.DVD-5|x86.Build.0 = Debug|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.Release|Any CPU.ActiveCfg = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.Release|Any CPU.Build.0 = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.Release|x64.ActiveCfg = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.Release|x64.Build.0 = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.Release|x86.ActiveCfg = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.Release|x86.Build.0 = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.SingleImage|Any CPU.ActiveCfg = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.SingleImage|Any CPU.Build.0 = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.SingleImage|x64.ActiveCfg = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.SingleImage|x64.Build.0 = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.SingleImage|x86.ActiveCfg = Release|Any CPU + {40085232-ACED-4CBE-945B-90BA8153C151}.SingleImage|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Artemis/Artemis/App.config b/Artemis/Artemis/App.config index 5db3e623b..20723b413 100644 --- a/Artemis/Artemis/App.config +++ b/Artemis/Artemis/App.config @@ -333,6 +333,10 @@ + + + + diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index e11609de2..9604e7fd8 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -143,36 +143,32 @@ ..\packages\Castle.Core.3.3.3\lib\net45\Castle.Core.dll True - - False - lib\ColorBox.dll - ..\packages\Colore.5.0.0\lib\net35\Corale.Colore.dll True - - ..\packages\CUE.NET.1.1.0\lib\net45\CUE.NET.dll + + ..\packages\CUE.NET.1.1.0.2\lib\net45\CUE.NET.dll True - - ..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.dll + + ..\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.dll True - - ..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.MsDelta.dll + + ..\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.MsDelta.dll True - - ..\packages\DeltaCompressionDotNet.1.0.0\lib\net45\DeltaCompressionDotNet.PatchApi.dll + + ..\packages\DeltaCompressionDotNet.1.1.0\lib\net20\DeltaCompressionDotNet.PatchApi.dll True - - ..\packages\DynamicExpresso.Core.1.3.1.0\lib\net40\DynamicExpresso.Core.dll + + ..\packages\DynamicExpresso.Core.1.3.3.4\lib\net40\DynamicExpresso.Core.dll True - - ..\packages\gong-wpf-dragdrop.0.1.4.3\lib\net40\GongSolutions.Wpf.DragDrop.dll + + ..\packages\gong-wpf-dragdrop.1.0.0\lib\net46\GongSolutions.Wpf.DragDrop.dll True @@ -187,27 +183,27 @@ ..\packages\log4net.2.0.5\lib\net45-full\log4net.dll True - - ..\packages\MahApps.Metro.1.2.4.0\lib\net45\MahApps.Metro.dll + + ..\packages\MahApps.Metro.1.3.0\lib\net45\MahApps.Metro.dll True False - ..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.dll + ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.dll True - ..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Mdb.dll + ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Mdb.dll True - ..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Pdb.dll + ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Pdb.dll True - ..\packages\Mono.Cecil.0.9.6.1\lib\net45\Mono.Cecil.Rocks.dll + ..\packages\Mono.Cecil.0.9.6.4\lib\net45\Mono.Cecil.Rocks.dll True @@ -239,7 +235,7 @@ True - ..\packages\NLog.4.3.7\lib\net45\NLog.dll + ..\packages\NLog.4.3.9\lib\net45\NLog.dll True @@ -247,7 +243,7 @@ True - ..\packages\Process.NET.1.0.1\lib\Process.NET.dll + ..\packages\Process.NET.1.0.5\lib\Process.NET.dll True @@ -255,7 +251,7 @@ True - ..\packages\SpotifyAPI-NET.2.11.0\lib\SpotifyAPI.dll + ..\packages\SpotifyAPI-NET.2.12.0\lib\SpotifyAPI.dll True @@ -273,7 +269,7 @@ - ..\packages\Caliburn.Micro.3.0.1\lib\net45\System.Windows.Interactivity.dll + ..\packages\MahApps.Metro.1.3.0\lib\net45\System.Windows.Interactivity.dll True @@ -296,30 +292,6 @@ - - ..\packages\Extended.Wpf.Toolkit.2.9\lib\net40\Xceed.Wpf.AvalonDock.dll - True - - - ..\packages\Extended.Wpf.Toolkit.2.9\lib\net40\Xceed.Wpf.AvalonDock.Themes.Aero.dll - True - - - ..\packages\Extended.Wpf.Toolkit.2.9\lib\net40\Xceed.Wpf.AvalonDock.Themes.Metro.dll - True - - - ..\packages\Extended.Wpf.Toolkit.2.9\lib\net40\Xceed.Wpf.AvalonDock.Themes.VS2010.dll - True - - - ..\packages\Extended.Wpf.Toolkit.2.9\lib\net40\Xceed.Wpf.DataGrid.dll - True - - - ..\packages\Extended.Wpf.Toolkit.2.9\lib\net40\Xceed.Wpf.Toolkit.dll - True - @@ -652,6 +624,9 @@ Code + + Designer + @@ -659,9 +634,6 @@ Designer - - Designer - @@ -678,8 +650,11 @@ - + + + Always + PreserveNewest @@ -865,9 +840,6 @@ - - PreserveNewest - @@ -886,14 +858,19 @@ false - + + + {40085232-aced-4cbe-945b-90ba8153c151} + ColorBox + + - + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - + diff --git a/Artemis/Artemis/Modules/Effects/Bubbles/BubblesViewModel.cs b/Artemis/Artemis/Modules/Effects/Bubbles/BubblesViewModel.cs index 378b26873..a0d2cb304 100644 --- a/Artemis/Artemis/Modules/Effects/Bubbles/BubblesViewModel.cs +++ b/Artemis/Artemis/Modules/Effects/Bubbles/BubblesViewModel.cs @@ -1,13 +1,35 @@ -using Artemis.Managers; +using System.Windows.Media; +using Artemis.Managers; using Artemis.ViewModels.Abstract; namespace Artemis.Modules.Effects.Bubbles { public sealed class BubblesViewModel : EffectViewModel { + private readonly BubblesModel _model; + private SolidColorBrush _bubbleColor; + public BubblesViewModel(MainManager main, BubblesModel model) : base(main, model) { + _model = model; DisplayName = "Bubbles"; + BubbleColor = new SolidColorBrush(model.Settings.BubbleColor); + } + + /// + /// The bubble color wrapped in a brush to allow color selection using ColorBox + /// + public Brush BubbleColor + { + get { return _bubbleColor; } + set + { + if (Equals(value, _bubbleColor)) return; + _bubbleColor = (SolidColorBrush) value; + + _model.Settings.BubbleColor = _bubbleColor.Color; + NotifyOfPropertyChange(() => BubbleColor); + } } } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeDataModel.cs b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeDataModel.cs index 20dd851d4..6e76b2e87 100644 --- a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeDataModel.cs +++ b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeDataModel.cs @@ -1,4 +1,5 @@ using Artemis.Models.Interfaces; +using Newtonsoft.Json; namespace Artemis.Modules.Games.CounterStrike { @@ -47,6 +48,10 @@ namespace Artemis.Modules.Games.CounterStrike public class State { + [JsonIgnore] + public bool made_kill { get; set; } + [JsonIgnore] + public bool made_headshot { get; set; } public int health { get; set; } public int armor { get; set; } public bool helmet { get; set; } @@ -58,15 +63,8 @@ namespace Artemis.Modules.Games.CounterStrike public int round_killhs { get; set; } } - public class Weapon0 - { - public string name { get; set; } - public string paintkit { get; set; } - public string type { get; set; } - public string state { get; set; } - } - public class Weapon1 + public class Weapon { public string name { get; set; } public string paintkit { get; set; } @@ -77,19 +75,12 @@ namespace Artemis.Modules.Games.CounterStrike public string state { get; set; } } - public class Weapon2 - { - public string name { get; set; } - public string paintkit { get; set; } - public string type { get; set; } - public string state { get; set; } - } - public class Weapons { - public Weapon0 weapon_0 { get; set; } - public Weapon1 weapon_1 { get; set; } - public Weapon2 weapon_2 { get; set; } + public Weapon active_weapon { get; set; } + public Weapon weapon_0 { get; set; } + public Weapon weapon_1 { get; set; } + public Weapon weapon_2 { get; set; } } public class MatchStats diff --git a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs index 8a7893c5d..6287b3e19 100644 --- a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs +++ b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeModel.cs @@ -12,6 +12,11 @@ namespace Artemis.Modules.Games.CounterStrike { public class CounterStrikeModel : GameModel { + private DateTime _lastHeadshot; + private int _lastHeadshots; + private DateTime _lastKill; + private int _lastKills; + public CounterStrikeModel(MainManager mainManager) : base(mainManager, SettingsProvider.Load(), new CounterStrikeDataModel()) { @@ -42,7 +47,46 @@ namespace Artemis.Modules.Games.CounterStrike public override void Update() { - // TODO: Set up active weapon in the datamodel + if (DataModel == null) + return; + + var dm = (CounterStrikeDataModel) DataModel; + if (dm.player != null) + { + // Detect active weapon + if (dm.player.weapons.weapon_0?.state == "active") + dm.player.weapons.active_weapon = dm.player.weapons.weapon_0; + else if (dm.player.weapons.weapon_1?.state == "active") + dm.player.weapons.active_weapon = dm.player.weapons.weapon_1; + else if (dm.player.weapons.weapon_2?.state == "active") + dm.player.weapons.active_weapon = dm.player.weapons.weapon_2; + + // Detect a kill + if (dm.player.state.round_kills > _lastKills) + { + dm.player.state.made_kill = true; + _lastKill = DateTime.Now; + } + else if (dm.player.state.made_kill && (DateTime.Now - _lastKill > TimeSpan.FromMilliseconds(500))) + dm.player.state.made_kill = false; + _lastKills = dm.player.state.round_kills; + + // Detect a headshot + if (dm.player.state.round_killhs > _lastHeadshots) + { + dm.player.state.made_headshot = true; + _lastHeadshot = DateTime.Now; + } + else if (dm.player.state.made_headshot && (DateTime.Now - _lastHeadshot > TimeSpan.FromMilliseconds(500))) + dm.player.state.made_headshot = false; + _lastHeadshots = dm.player.state.round_killhs; + + // Detect a round win + + // Detect a round loss + } + + DataModel = dm; } public void HandleGameData(object sender, GameDataReceivedEventArgs e) @@ -56,7 +100,9 @@ namespace Artemis.Modules.Games.CounterStrike // Parse the JSON try { - DataModel = JsonConvert.DeserializeObject(jsonString); + if (DataModel == null) + DataModel = new CounterStrikeDataModel(); + JsonConvert.PopulateObject(jsonString, DataModel); } catch (Exception ex) { diff --git a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs index 32647e4bb..8da2d0d0d 100644 --- a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs +++ b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueModel.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using Artemis.DAL; using Artemis.Managers; @@ -7,6 +8,7 @@ using Artemis.Profiles.Layers.Models; using Artemis.Settings; using Artemis.Utilities; using Artemis.Utilities.Memory; +using Newtonsoft.Json; namespace Artemis.Modules.Games.RocketLeague { @@ -25,20 +27,20 @@ namespace Artemis.Modules.Games.RocketLeague Initialized = false; // Generate a new offset when the game is updated -// var offset = new GamePointersCollection -// { -// Game = "RocketLeague", -// GameVersion = "1.21", -// GameAddresses = new List -// { -// new GamePointer -// { -// Description = "Boost", -// BasePointer = new IntPtr(0x016AD528), -// Offsets = new[] {0x304, 0x8, 0x50, 0x720, 0x224} -// } -// } -// }; + //var offset = new GamePointersCollection + //{ + // Game = "RocketLeague", + // GameVersion = "1.24", + // GameAddresses = new List + // { + // new GamePointer + // { + // Description = "Boost", + // BasePointer = new IntPtr(0x016BBFB4), + // Offsets = new[] { 0xc4, 0x210, 0x320, 0x734, 0x224} + // } + // } + //}; //var res = JsonConvert.SerializeObject(offset, Formatting.Indented); } diff --git a/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs b/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs index 546d47426..ad4403d55 100644 --- a/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs +++ b/Artemis/Artemis/Modules/Games/WoW/WoWModel.cs @@ -8,7 +8,9 @@ using Artemis.Modules.Games.WoW.Data; using Artemis.Profiles.Layers.Models; using Artemis.Settings; using Artemis.Utilities.Memory; +using Newtonsoft.Json; using Process.NET; +using Process.NET.Memory; namespace Artemis.Modules.Games.WoW { @@ -31,25 +33,36 @@ namespace Artemis.Modules.Games.WoW Initialized = false; - // TODO: Retrieve from GitHub - _pointer = new GamePointersCollection - { - Game = "WorldOfWarcraft", - GameVersion = "7.0.3.22522", - GameAddresses = new List - { - new GamePointer - { - Description = "ObjectManager", - BasePointer = new IntPtr(0x1575E10) - }, - new GamePointer - { - Description = "LocalPlayer", - BasePointer = new IntPtr(0x169BCB0) - } - } - }; + _pointer = SettingsProvider.Load().WorldOfWarcraft; + //_pointer = new GamePointersCollection + //{ + // Game = "WorldOfWarcraft", + // GameVersion = "7.0.3.22810", + // GameAddresses = new List + // { + // new GamePointer + // { + // Description = "ObjectManager", + // BasePointer = new IntPtr(0x1578070) + // }, + // new GamePointer + // { + // Description = "LocalPlayer", + // BasePointer = new IntPtr(0x169DF10) + // }, + // new GamePointer + // { + // Description = "NameCache", + // BasePointer = new IntPtr(0x151DCE8) + // }, + // new GamePointer + // { + // Description = "TargetGuid", + // BasePointer = new IntPtr(0x179C940) + // } + // } + //}; + //var res = JsonConvert.SerializeObject(_pointer, Formatting.Indented); } public int Scale { get; set; } @@ -68,8 +81,7 @@ namespace Artemis.Modules.Games.WoW if (tempProcess == null) return; - _process = new ProcessSharp(tempProcess); - _process.Memory = new ExternalProcessMemory(_process.Handle); + _process = new ProcessSharp(tempProcess, MemoryType.Remote); Initialized = true; } @@ -83,10 +95,11 @@ namespace Artemis.Modules.Games.WoW var objectManager = new WoWObjectManager(_process, _pointer.GameAddresses.First(a => a.Description == "ObjectManager").BasePointer); - var nameCache = new WoWNameCache(_process, new IntPtr(0x151BA88)); + var nameCache = new WoWNameCache(_process, + _pointer.GameAddresses.First(a => a.Description == "NameCache").BasePointer); var player = new WoWPlayer(_process, - _pointer.GameAddresses.First(a => a.Description == "LocalPlayer").BasePointer, new IntPtr(0x179A6E0), - true); + _pointer.GameAddresses.First(a => a.Description == "LocalPlayer").BasePointer, + _pointer.GameAddresses.First(a => a.Description == "TargetGuid").BasePointer, true); dataModel.Player = player; if (dataModel.Player != null && dataModel.Player.Guid != Guid.Empty) diff --git a/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplayModel.cs b/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplayModel.cs index d19c336c9..e5d2de8d7 100644 --- a/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplayModel.cs +++ b/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplayModel.cs @@ -2,6 +2,7 @@ using System.Drawing; using System.Runtime.InteropServices; using System.Windows.Forms; +using Artemis.DAL; using Artemis.Managers; using Artemis.Models; using Artemis.Profiles.Layers.Models; @@ -12,13 +13,15 @@ namespace Artemis.Modules.Overlays.VolumeDisplay { public class VolumeDisplayModel : OverlayModel { - public VolumeDisplayModel(MainManager mainManager) : base(mainManager, new VolumeDisplaySettings()) + public VolumeDisplayModel(MainManager mainManager) + : base(mainManager, SettingsProvider.Load()) { Name = "VolumeDisplay"; - - VolumeDisplay = new VolumeBar(MainManager.DeviceManager, (VolumeDisplaySettings) Settings); + Settings = (VolumeDisplaySettings) base.Settings; + VolumeDisplay = new VolumeBar(MainManager.DeviceManager, Settings); } + public new VolumeDisplaySettings Settings { get; set; } public VolumeBar VolumeDisplay { get; set; } public override void Dispose() @@ -67,7 +70,7 @@ namespace Artemis.Modules.Overlays.VolumeDisplay private void KeyPressTask(KeyEventArgs e) { - if (e.KeyCode != Keys.VolumeUp && e.KeyCode != Keys.VolumeDown) + if ((e.KeyCode != Keys.VolumeUp) && (e.KeyCode != Keys.VolumeDown)) return; VolumeDisplay.Ttl = 1000; @@ -76,7 +79,7 @@ namespace Artemis.Modules.Overlays.VolumeDisplay public override void RenderOverlay(RenderFrame frame, bool keyboardOnly) { - if (MainManager.DeviceManager.ActiveKeyboard == null || VolumeDisplay == null || VolumeDisplay.Ttl < 1) + if ((MainManager.DeviceManager.ActiveKeyboard == null) || (VolumeDisplay == null) || (VolumeDisplay.Ttl < 1)) return; using (var g = Graphics.FromImage(frame.KeyboardBitmap)) diff --git a/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplaySettings.cs b/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplaySettings.cs index a67eb0d12..2a5de5b80 100644 --- a/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplaySettings.cs +++ b/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplaySettings.cs @@ -1,5 +1,7 @@ using System.Windows.Media; +using Artemis.DAL; using Artemis.Settings; +using Newtonsoft.Json; namespace Artemis.Modules.Overlays.VolumeDisplay { @@ -7,5 +9,19 @@ namespace Artemis.Modules.Overlays.VolumeDisplay { public Color MainColor { get; set; } public Color SecondaryColor { get; set; } + + public new void Reset(bool save = false) + { + JsonConvert.PopulateObject("{}", this, new JsonSerializerSettings + { + ObjectCreationHandling = ObjectCreationHandling.Reuse + }); + + MainColor = Colors.Red; + SecondaryColor = Colors.GreenYellow; + + if (save) + SettingsProvider.Save(this); + } } } \ No newline at end of file diff --git a/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplayView.xaml b/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplayView.xaml index 51226f2cc..3cdcdd1f9 100644 --- a/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplayView.xaml +++ b/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplayView.xaml @@ -5,6 +5,7 @@ xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit" xmlns:cal="http://www.caliburnproject.org" + xmlns:ncore="http://schemas.ncore.com/wpf/xaml/colorbox" mc:Ignorable="d" d:DesignHeight="476.986" d:DesignWidth="538.772"> @@ -42,21 +43,19 @@ Margin="0,8"> Main volume display color - - + + Secondary volume display color - - + + diff --git a/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplayViewModel.cs b/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplayViewModel.cs index 5004e0c87..1296521ed 100644 --- a/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplayViewModel.cs +++ b/Artemis/Artemis/Modules/Overlays/VolumeDisplay/VolumeDisplayViewModel.cs @@ -1,13 +1,48 @@ -using Artemis.Managers; +using System.Windows.Media; +using Artemis.Managers; using Artemis.ViewModels.Abstract; namespace Artemis.Modules.Overlays.VolumeDisplay { public sealed class VolumeDisplayViewModel : OverlayViewModel { + private readonly VolumeDisplayModel _model; + private SolidColorBrush _mainColor; + private SolidColorBrush _secondaryColor; + public VolumeDisplayViewModel(MainManager mainManager, VolumeDisplayModel model) : base(mainManager, model) { + _model = model; DisplayName = "Volume Display"; + + MainColor = new SolidColorBrush(model.Settings.MainColor); + SecondaryColor = new SolidColorBrush(model.Settings.SecondaryColor); + } + + public Brush MainColor + { + get { return _mainColor; } + set + { + if (Equals(value, _mainColor)) return; + _mainColor = (SolidColorBrush) value; + + _model.Settings.MainColor = _mainColor.Color; + NotifyOfPropertyChange(() => MainColor); + } + } + + public Brush SecondaryColor + { + get { return _secondaryColor; } + set + { + if (Equals(value, _secondaryColor)) return; + _secondaryColor = (SolidColorBrush) value; + + _model.Settings.SecondaryColor = _secondaryColor.Color; + NotifyOfPropertyChange(() => SecondaryColor); + } } } } \ No newline at end of file diff --git a/Artemis/Artemis/NLog.xsd b/Artemis/Artemis/NLog.xsd index c489255c0..faa9681c6 100644 --- a/Artemis/Artemis/NLog.xsd +++ b/Artemis/Artemis/NLog.xsd @@ -368,6 +368,7 @@ + @@ -401,6 +402,11 @@ Instance of that is used to format log messages. + + + End of line value if a newline is appended at the end of log message . + + Maximum message size in bytes. @@ -1021,8 +1027,11 @@ - + + + + @@ -1032,15 +1041,15 @@ - + + - @@ -1102,9 +1111,14 @@ Maximum number of archive files that should be kept. - + - Gets or set a value indicating whether a managed file stream is forced, instead of used the native implementation. + Is the an absolute or relative path? + + + + + Is the an absolute or relative path? @@ -1112,6 +1126,16 @@ Cleanup invalid values in a filename, e.g. slashes in a filename. If set to true, this can impact the performance of massive writes. If set to false, nothing gets written when the filename is wrong. + + + Gets or set a value indicating whether a managed file stream is forced, instead of used the native implementation. + + + + + Indicates whether the footer should be written only when the file is archived. + + Name of the file to write to. @@ -1157,9 +1181,9 @@ Indicates whether concurrent writes to the log file by multiple processes on the same host. - + - Delay in milliseconds to wait before attempting to write to the file again. + Indicates whether to keep log file open instead of opening and closing it on each logging event. @@ -1192,16 +1216,16 @@ Indicates whether to automatically flush the file buffers after each log message. + + + Delay in milliseconds to wait before attempting to write to the file again. + + Number of times the write is appended on the file before NLog discards the log message. - - - Indicates whether to keep log file open instead of opening and closing it on each logging event. - - @@ -1223,6 +1247,13 @@ + + + + + + + @@ -1703,6 +1734,7 @@ + @@ -1728,6 +1760,11 @@ Encoding to be used. + + + End of line value if a newline is appended at the end of log message . + + Maximum message size in bytes. @@ -1783,6 +1820,7 @@ + @@ -1816,6 +1854,11 @@ Instance of that is used to format log messages. + + + End of line value if a newline is appended at the end of log message . + + Maximum message size in bytes. diff --git a/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs b/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs index 5a7adc7d0..0f2ae4d53 100644 --- a/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs +++ b/Artemis/Artemis/Profiles/Layers/Conditions/EventCondition.cs @@ -9,13 +9,16 @@ namespace Artemis.Profiles.Layers.Conditions { public bool ConditionsMet(LayerModel layer, IDataModel dataModel) { - var conditionsMet = layer.Properties.Conditions.All(cm => cm.ConditionMet(dataModel)); - layer.EventProperties.Update(layer, conditionsMet); + lock (layer.Properties.Conditions) + { + var conditionsMet = layer.Properties.Conditions.All(cm => cm.ConditionMet(dataModel)); + layer.EventProperties.Update(layer, conditionsMet); - if (conditionsMet && layer.EventProperties.MustTrigger) - layer.EventProperties.TriggerEvent(layer); + if (conditionsMet && layer.EventProperties.CanTrigger) + layer.EventProperties.TriggerEvent(layer); - return conditionsMet && layer.EventProperties.MustDraw; + return layer.EventProperties.MustDraw; + } } } } \ No newline at end of file diff --git a/Artemis/Artemis/Profiles/Layers/Models/EventPropertiesModel.cs b/Artemis/Artemis/Profiles/Layers/Models/EventPropertiesModel.cs index 8acd950da..b13f3487a 100644 --- a/Artemis/Artemis/Profiles/Layers/Models/EventPropertiesModel.cs +++ b/Artemis/Artemis/Profiles/Layers/Models/EventPropertiesModel.cs @@ -1,4 +1,6 @@ using System; +using System.Threading; +using System.Threading.Tasks; using Newtonsoft.Json; namespace Artemis.Profiles.Layers.Models @@ -10,10 +12,10 @@ namespace Artemis.Profiles.Layers.Models public TimeSpan TriggerDelay { get; set; } [JsonIgnore] - public bool MustTrigger { get; set; } + public bool CanTrigger { get; set; } [JsonIgnore] - public DateTime AnimationStart { get; set; } + public DateTime EventTriggerTime { get; set; } [JsonIgnore] public bool MustDraw { get; set; } @@ -21,23 +23,70 @@ namespace Artemis.Profiles.Layers.Models /// /// Resets the event's properties and triggers it /// - public abstract void TriggerEvent(LayerModel layer); + public virtual void TriggerEvent(LayerModel layer) + { + if (!CanTrigger) + return; + + if (TriggerDelay > TimeSpan.Zero) + { + if (EventCanTriggerTime == DateTime.MinValue) + EventCanTriggerTime = DateTime.Now; + + if (DateTime.Now - EventCanTriggerTime < TriggerDelay) + return; + + EventCanTriggerTime = DateTime.MinValue; + } + + CanTrigger = false; + MustDraw = true; + EventTriggerTime = DateTime.Now; + layer.Properties.AnimationProgress = 0.0; + } + + public DateTime EventCanTriggerTime { get; set; } + /// /// Gets whether the event should stop /// /// /// - public abstract bool MustStop(LayerModel layer); + public virtual bool MustStop(LayerModel layer) + { + if (ExpirationType == ExpirationType.Time) + { + if (EventTriggerTime == DateTime.MinValue) + return false; + return DateTime.Now - EventTriggerTime > Length; + } + if (ExpirationType == ExpirationType.Animation) + return (layer.LayerAnimation == null) || layer.LayerAnimation.MustExpire(layer); + + return true; + } // Called every frame, if parent conditions met. public void Update(LayerModel layerModel, bool conditionsMet) { - if (MustStop(layerModel)) + if (EventCanTriggerTime > DateTime.MinValue && (DateTime.Now - EventCanTriggerTime > TriggerDelay)) + { + CanTrigger = true; + TriggerEvent(layerModel); + return; + } + + if (MustDraw && MustStop(layerModel)) MustDraw = false; if (!conditionsMet) - MustTrigger = true; + CanTrigger = true; + } + + protected bool DelayExpired() + { + return EventCanTriggerTime > DateTime.MinValue && DateTime.Now - EventCanTriggerTime >= TriggerDelay; } } diff --git a/Artemis/Artemis/Profiles/Layers/Models/KeyboardEventPropertiesModel.cs b/Artemis/Artemis/Profiles/Layers/Models/KeyboardEventPropertiesModel.cs index ce0cb8bd2..76c9cfb08 100644 --- a/Artemis/Artemis/Profiles/Layers/Models/KeyboardEventPropertiesModel.cs +++ b/Artemis/Artemis/Profiles/Layers/Models/KeyboardEventPropertiesModel.cs @@ -1,5 +1,4 @@ using System; -using Artemis.Profiles.Layers.Types.Keyboard; using Artemis.Profiles.Layers.Types.KeyboardGif; namespace Artemis.Profiles.Layers.Models @@ -8,40 +7,23 @@ namespace Artemis.Profiles.Layers.Models { 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; + if (CanTrigger && DelayExpired()) + { + if (layer.GifImage != null) + layer.GifImage.CurrentFrame = 0; + } - MustTrigger = false; - MustDraw = true; - keyboardProperties.AnimationProgress = 0.0; - if (layer.GifImage != null) - layer.GifImage.CurrentFrame = 0; + base.TriggerEvent(layer); } 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"); + if (ExpirationType != ExpirationType.Animation) + return base.MustStop(layer); - 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; - } + if (layer.LayerType is KeyboardGifType) + return layer.GifImage?.CurrentFrame >= layer.GifImage?.FrameCount - 1; + return (layer.LayerAnimation == null) || layer.LayerAnimation.MustExpire(layer); } } } \ No newline at end of file diff --git a/Artemis/Artemis/Profiles/Layers/Models/LayerModel.cs b/Artemis/Artemis/Profiles/Layers/Models/LayerModel.cs index 68d968013..e3bd0b529 100644 --- a/Artemis/Artemis/Profiles/Layers/Models/LayerModel.cs +++ b/Artemis/Artemis/Profiles/Layers/Models/LayerModel.cs @@ -242,5 +242,13 @@ namespace Artemis.Profiles.Layers.Models } #endregion + + public void SetupCondition() + { + if (IsEvent && !(LayerCondition is EventCondition)) + LayerCondition = new EventCondition(); + else if (!IsEvent && !(LayerCondition is DataModelCondition)) + LayerCondition = new DataModelCondition(); + } } } \ No newline at end of file diff --git a/Artemis/Artemis/Profiles/Layers/Types/Generic/GenericPropertiesView.xaml b/Artemis/Artemis/Profiles/Layers/Types/Generic/GenericPropertiesView.xaml index 9747459ea..c31f063c2 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/Generic/GenericPropertiesView.xaml +++ b/Artemis/Artemis/Profiles/Layers/Types/Generic/GenericPropertiesView.xaml @@ -1,9 +1,10 @@ - @@ -23,54 +24,46 @@ + VerticalAlignment="Center" + Height="18" /> + Height="22"> - + + VerticalAlignment="Center" Height="18" /> + TickPlacement="None" TickFrequency="0.05" + Value="{Binding LayerModel.Properties.AnimationSpeed, Mode=TwoWay}" Minimum="0.05" Maximum="3" + SmallChange="0" IsSnapToTickEnabled="True" Margin="10,12,10,2" Height="24" /> + VerticalAlignment="Top" Height="18" Width="130" /> - + BorderThickness="1" SnapsToDevicePixels="True" ToolTip="Click to edit"> + \ No newline at end of file diff --git a/Artemis/Artemis/Profiles/Layers/Types/Generic/GenericPropertiesViewModel.cs b/Artemis/Artemis/Profiles/Layers/Types/Generic/GenericPropertiesViewModel.cs index 80c7aa4ec..ae0d4a389 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/Generic/GenericPropertiesViewModel.cs +++ b/Artemis/Artemis/Profiles/Layers/Types/Generic/GenericPropertiesViewModel.cs @@ -1,13 +1,16 @@ -using System.Linq; +using System.Collections.Generic; +using System.Linq; using Artemis.Profiles.Layers.Abstract; using Artemis.Profiles.Layers.Interfaces; using Artemis.ViewModels.Profiles; using Caliburn.Micro; +using ColorBox; namespace Artemis.Profiles.Layers.Types.Generic { public class GenericPropertiesViewModel : LayerPropertiesViewModel { + private IEnumerable _availableBrushTypes; private ILayerAnimation _selectedLayerAnimation; public GenericPropertiesViewModel(LayerEditorViewModel editorVm) : base(editorVm) diff --git a/Artemis/Artemis/Profiles/Layers/Types/Keyboard/KeyboardPropertiesView.xaml b/Artemis/Artemis/Profiles/Layers/Types/Keyboard/KeyboardPropertiesView.xaml index 9e582617b..85ee67746 100644 --- a/Artemis/Artemis/Profiles/Layers/Types/Keyboard/KeyboardPropertiesView.xaml +++ b/Artemis/Artemis/Profiles/Layers/Types/Keyboard/KeyboardPropertiesView.xaml @@ -60,7 +60,7 @@ VerticalAlignment="Top" Height="18" Width="130" /> - + diff --git a/Artemis/Artemis/Properties/AssemblyInfo.cs b/Artemis/Artemis/Properties/AssemblyInfo.cs index 8bdcdc28e..7be9c3d37 100644 --- a/Artemis/Artemis/Properties/AssemblyInfo.cs +++ b/Artemis/Artemis/Properties/AssemblyInfo.cs @@ -52,5 +52,5 @@ using System.Windows; // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.3.3.0")] -[assembly: AssemblyFileVersion("1.3.3.0")] \ No newline at end of file +[assembly: AssemblyVersion("1.4.0.0")] +[assembly: AssemblyFileVersion("1.4.0.0")] \ No newline at end of file diff --git a/Artemis/Artemis/Resources/Keyboards/default-profiles.zip b/Artemis/Artemis/Resources/Keyboards/default-profiles.zip index 6dc6e025f..ac8cd394b 100644 Binary files a/Artemis/Artemis/Resources/Keyboards/default-profiles.zip and b/Artemis/Artemis/Resources/Keyboards/default-profiles.zip differ diff --git a/Artemis/Artemis/Settings/GeneralSettings.cs b/Artemis/Artemis/Settings/GeneralSettings.cs index 2717b7be6..189bb025f 100644 --- a/Artemis/Artemis/Settings/GeneralSettings.cs +++ b/Artemis/Artemis/Settings/GeneralSettings.cs @@ -27,6 +27,10 @@ namespace Artemis.Settings [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] public string LastKeyboard { get; set; } + [DefaultValue("Qwerty")] + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] + public string Layout { get; set; } + [DefaultValue(true)] [JsonProperty(DefaultValueHandling = DefaultValueHandling.Populate)] public bool EnablePointersUpdate { get; set; } diff --git a/Artemis/Artemis/Settings/OffsetSettings.cs b/Artemis/Artemis/Settings/OffsetSettings.cs index 68ec07922..14a63bee0 100644 --- a/Artemis/Artemis/Settings/OffsetSettings.cs +++ b/Artemis/Artemis/Settings/OffsetSettings.cs @@ -7,6 +7,7 @@ namespace Artemis.Settings public class OffsetSettings : IArtemisSettings { public GamePointersCollection RocketLeague { get; set; } + public GamePointersCollection WorldOfWarcraft { get; set; } public void Save() { diff --git a/Artemis/Artemis/Styles/ColorBox.xaml b/Artemis/Artemis/Styles/ColorBox.xaml index bbd797280..6c8f49fea 100644 --- a/Artemis/Artemis/Styles/ColorBox.xaml +++ b/Artemis/Artemis/Styles/ColorBox.xaml @@ -207,7 +207,7 @@ + ItemsSource="{Binding AvailableBrushTypes, RelativeSource={RelativeSource TemplatedParent}}" HorizontalAlignment="Center"> @@ -219,7 +219,7 @@ + Padding="0,3" Margin="3,0"> + + - - + + + + + + + + + + + @@ -649,14 +758,6 @@ Value="{Binding EndY, RelativeSource={RelativeSource TemplatedParent}}" /> - - - - @@ -676,17 +777,15 @@ - + - - - + @@ -707,14 +806,6 @@ - - - - diff --git a/Artemis/Artemis/Utilities/Logging.cs b/Artemis/Artemis/Utilities/Logging.cs index 50b2a84b1..8d6040a3b 100644 --- a/Artemis/Artemis/Utilities/Logging.cs +++ b/Artemis/Artemis/Utilities/Logging.cs @@ -27,9 +27,10 @@ namespace Artemis.Utilities debuggerTarget.Layout = @"${logger:shortName=True} - ${uppercase:${level}}: ${message}"; fileTarget.FileName = "${specialfolder:folder=MyDocuments}/Artemis/logs/${shortdate}.txt"; fileTarget.Layout = "${longdate}|${level:uppercase=true}|${logger}|${message} ${exception:format=tostring}"; - fileTarget.ArchiveEvery = FileArchivePeriod.Day; + fileTarget.EnableFileDelete = true; fileTarget.MaxArchiveFiles = 7; - + fileTarget.ArchiveEvery = FileArchivePeriod.Minute; + // Step 4. Define rules var rule1 = new LoggingRule("*", logLevel, debuggerTarget); config.LoggingRules.Add(rule1); diff --git a/Artemis/Artemis/Utilities/Updater.cs b/Artemis/Artemis/Utilities/Updater.cs index 43cb0e242..fe9b5f51d 100644 --- a/Artemis/Artemis/Utilities/Updater.cs +++ b/Artemis/Artemis/Utilities/Updater.cs @@ -147,6 +147,8 @@ namespace Artemis.Utilities // Assign each pointer to the settings file if (pointers.FirstOrDefault(p => p.Game == "RocketLeague") != null) offsetSettings.RocketLeague = pointers.FirstOrDefault(p => p.Game == "RocketLeague"); + if (pointers.FirstOrDefault(p => p.Game == "WorldOfWarcraft") != null) + offsetSettings.WorldOfWarcraft = pointers.FirstOrDefault(p => p.Game == "WorldOfWarcraft"); offsetSettings.Save(); } diff --git a/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs b/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs index 941165ded..61d9ba4d7 100644 --- a/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs +++ b/Artemis/Artemis/ViewModels/Flyouts/FlyoutSettingsViewModel.cs @@ -86,6 +86,12 @@ namespace Artemis.ViewModels.Flyouts "Corsair Dark" }; + public BindableCollection Layouts => new BindableCollection + { + "Qwerty", + "Azerty" + }; + public string VersionText => "Artemis " + Assembly.GetExecutingAssembly().GetName().Version; public BindableCollection LogLevels { get; set; } @@ -101,6 +107,17 @@ namespace Artemis.ViewModels.Flyouts } } + public string SelectedLayout + { + get { return GeneralSettings.Layout; } + set + { + if (value == GeneralSettings.Layout) return; + GeneralSettings.Layout = value; + NotifyOfPropertyChange(() => SelectedLayout); + } + } + public string SelectedLogLevel { get { return GeneralSettings.LogLevel; } diff --git a/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs index 839e84abc..aac0629c6 100644 --- a/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/LayerEditorViewModel.cs @@ -5,6 +5,7 @@ using System.IO; using System.Linq; using Artemis.Models.Interfaces; using Artemis.Profiles.Layers.Abstract; +using Artemis.Profiles.Layers.Conditions; using Artemis.Profiles.Layers.Interfaces; using Artemis.Profiles.Layers.Models; using Artemis.Profiles.Layers.Types.Keyboard; @@ -175,7 +176,9 @@ namespace Artemis.ViewModels.Profiles // TODO: EventPropVM must have layer too if (EventPropertiesViewModel != null) Layer.EventProperties = EventPropertiesViewModel.GetAppliedProperties(); - + + Layer.SetupCondition(); + // Don't bother checking for a GIF path unless the type is GIF if (!(Layer.LayerType is KeyboardGifType)) return; @@ -215,6 +218,11 @@ namespace Artemis.ViewModels.Profiles // that would upset the child layers' relations (sounds like Dr. Phil amirite?) var currentObj = Clone(Layer); currentObj.Children.Clear(); + + // Apply the IsEvent boolean + currentObj.SetupCondition(); + ProposedLayer.SetupCondition(); + var current = JsonConvert.SerializeObject(currentObj, Formatting.Indented); var proposed = JsonConvert.SerializeObject(ProposedLayer, Formatting.Indented); diff --git a/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs index cbce56fdc..0fd5e12ff 100644 --- a/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs @@ -546,8 +546,13 @@ namespace Artemis.ViewModels.Profiles return; var newProfile = GeneralHelpers.Clone(SelectedProfile); - newProfile.Name = - await DialogService.ShowInputDialog("Duplicate profile", "Please enter a unique profile name"); + newProfile.Name = await DialogService + .ShowInputDialog("Duplicate profile", "Please enter a unique profile name"); + + // Null when the user cancelled + if (string.IsNullOrEmpty(newProfile.Name)) + return; + // Verify the name while (ProfileProvider.GetAll().Contains(newProfile)) { @@ -555,7 +560,7 @@ namespace Artemis.ViewModels.Profiles await DialogService.ShowInputDialog("Name already in use", "Please enter a unique profile name"); // Null when the user cancelled - if (string.IsNullOrEmpty(SelectedProfile.Name)) + if (string.IsNullOrEmpty(newProfile.Name)) return; } diff --git a/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml b/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml index 34b66d7a6..b61361692 100644 --- a/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml +++ b/Artemis/Artemis/Views/Flyouts/FlyoutSettingsView.xaml @@ -7,7 +7,7 @@ xmlns:cal="http://www.caliburnproject.org" mc:Ignorable="d" d:DesignHeight="600" d:DesignWidth="300" - Width="300"> + Width="270"> @@ -31,23 +31,27 @@ + + + + + + \ No newline at end of file diff --git a/Artemis/ColorBox/UpDownBase.cs b/Artemis/ColorBox/UpDownBase.cs new file mode 100644 index 000000000..72228437d --- /dev/null +++ b/Artemis/ColorBox/UpDownBase.cs @@ -0,0 +1,653 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; +using System.Globalization; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Input; + +namespace ColorBox +{ + [TemplatePart(Name = PartTextBox, Type = typeof(TextBox))] + [TemplatePart(Name = PartSpinner, Type = typeof(Spinner))] + public abstract class UpDownBase : Control, IValidateInput + { + #region Event Handlers + + private void OnSpinnerSpin(object sender, SpinEventArgs e) + { + if (AllowSpin && !IsReadOnly) + OnSpin(e); + } + + #endregion + + #region Members + + internal const string PartTextBox = "PART_TextBox"; + internal const string PartSpinner = "PART_Spinner"; + private bool _isSyncingTextAndValueProperties; + private bool _isTextChangedFromUi; + + #endregion + + #region Properties + + internal Spinner Spinner { get; private set; } + + internal TextBox TextBox { get; private set; } + + #region CultureInfo + + public static readonly DependencyProperty CultureInfoProperty = DependencyProperty.Register("CultureInfo", + typeof(CultureInfo), typeof(UpDownBase), + new UIPropertyMetadata(CultureInfo.CurrentCulture, OnCultureInfoChanged)); + + public CultureInfo CultureInfo + { + get { return (CultureInfo) GetValue(CultureInfoProperty); } + set { SetValue(CultureInfoProperty, value); } + } + + private static void OnCultureInfoChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) + { + var inputBase = o as UpDownBase; + if (inputBase != null) + inputBase.OnCultureInfoChanged((CultureInfo) e.OldValue, (CultureInfo) e.NewValue); + } + + #endregion //CultureInfo + + #region IsReadOnly + + public static readonly DependencyProperty IsReadOnlyProperty = DependencyProperty.Register("IsReadOnly", + typeof(bool), typeof(UpDownBase), new UIPropertyMetadata(false, OnReadOnlyChanged)); + + public bool IsReadOnly + { + get { return (bool) GetValue(IsReadOnlyProperty); } + set { SetValue(IsReadOnlyProperty, value); } + } + + private static void OnReadOnlyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) + { + var inputBase = o as UpDownBase; + if (inputBase != null) + inputBase.OnReadOnlyChanged((bool) e.OldValue, (bool) e.NewValue); + } + + #endregion //IsReadOnly + + #region Text + + public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), + typeof(UpDownBase), + new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, + OnTextChanged, null, false, UpdateSourceTrigger.LostFocus)); + + public string Text + { + get { return (string) GetValue(TextProperty); } + set { SetValue(TextProperty, value); } + } + + private static void OnTextChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) + { + var inputBase = o as UpDownBase; + if (inputBase != null) + inputBase.OnTextChanged((string) e.OldValue, (string) e.NewValue); + } + + #endregion //Text + + #region FormatString + + public static readonly DependencyProperty FormatStringProperty = DependencyProperty.Register("FormatString", + typeof(string), typeof(UpDownBase), new UIPropertyMetadata(string.Empty, OnFormatStringChanged)); + + public string FormatString + { + get { return (string) GetValue(FormatStringProperty); } + set { SetValue(FormatStringProperty, value); } + } + + private static void OnFormatStringChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) + { + var numericUpDown = o as UpDownBase; + if (numericUpDown != null) + numericUpDown.OnFormatStringChanged((string) e.OldValue, (string) e.NewValue); + } + + protected virtual void OnFormatStringChanged(string oldValue, string newValue) + { + if (IsInitialized) + SyncTextAndValue(false, null); + } + + #endregion //FormatString + + #region Increment + + public static readonly DependencyProperty IncrementProperty = DependencyProperty.Register("Increment", + typeof(double?), typeof(UpDownBase), + new PropertyMetadata(default(double), OnIncrementChanged, OnCoerceIncrement)); + + public double? Increment + { + get { return (double?) GetValue(IncrementProperty); } + set { SetValue(IncrementProperty, value); } + } + + private static void OnIncrementChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) + { + var numericUpDown = o as UpDownBase; + if (numericUpDown != null) + numericUpDown.OnIncrementChanged((double) e.OldValue, (double) e.NewValue); + } + + protected virtual void OnIncrementChanged(double oldValue, double newValue) + { + if (IsInitialized) + SetValidSpinDirection(); + } + + private static object OnCoerceIncrement(DependencyObject d, object baseValue) + { + var numericUpDown = d as UpDownBase; + if (numericUpDown != null) + return numericUpDown.OnCoerceIncrement((double) baseValue); + + return baseValue; + } + + protected virtual double? OnCoerceIncrement(double? baseValue) + { + return baseValue; + } + + #endregion + + #region Maximum + + public static readonly DependencyProperty MaximumProperty = DependencyProperty.Register("Maximum", + typeof(double), typeof(UpDownBase), + new UIPropertyMetadata(default(double), OnMaximumChanged, OnCoerceMaximum)); + + public double Maximum + { + get { return (double) GetValue(MaximumProperty); } + set { SetValue(MaximumProperty, value); } + } + + private static void OnMaximumChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) + { + var numericUpDown = o as UpDownBase; + if (numericUpDown != null) + numericUpDown.OnMaximumChanged((double) e.OldValue, (double) e.NewValue); + } + + protected virtual void OnMaximumChanged(double oldValue, double newValue) + { + if (IsInitialized) + SetValidSpinDirection(); + } + + private static object OnCoerceMaximum(DependencyObject d, object baseValue) + { + var numericUpDown = d as UpDownBase; + if (numericUpDown != null) + return numericUpDown.OnCoerceMaximum((double) baseValue); + + return baseValue; + } + + protected virtual double OnCoerceMaximum(double baseValue) + { + return baseValue; + } + + #endregion //Maximum + + #region Minimum + + public static readonly DependencyProperty MinimumProperty = DependencyProperty.Register("Minimum", + typeof(double), typeof(UpDownBase), + new UIPropertyMetadata(default(double), OnMinimumChanged, OnCoerceMinimum)); + + public double Minimum + { + get { return (double) GetValue(MinimumProperty); } + set { SetValue(MinimumProperty, value); } + } + + private static void OnMinimumChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) + { + var numericUpDown = o as UpDownBase; + if (numericUpDown != null) + numericUpDown.OnMinimumChanged((double) e.OldValue, (double) e.NewValue); + } + + protected virtual void OnMinimumChanged(double oldValue, double newValue) + { + if (IsInitialized) + SetValidSpinDirection(); + } + + private static object OnCoerceMinimum(DependencyObject d, object baseValue) + { + var numericUpDown = d as UpDownBase; + if (numericUpDown != null) + return numericUpDown.OnCoerceMinimum((double) baseValue); + + return baseValue; + } + + protected virtual double? OnCoerceMinimum(double baseValue) + { + return baseValue; + } + + #endregion //Minimum + + #region AllowSpin + + public static readonly DependencyProperty AllowSpinProperty = DependencyProperty.Register("AllowSpin", + typeof(bool), typeof(UpDownBase), new UIPropertyMetadata(true)); + + public bool AllowSpin + { + get { return (bool) GetValue(AllowSpinProperty); } + set { SetValue(AllowSpinProperty, value); } + } + + #endregion //AllowSpin + + #region DefaultValue + + public static readonly DependencyProperty DefaultValueProperty = DependencyProperty.Register("DefaultValue", + typeof(double?), typeof(UpDownBase), new UIPropertyMetadata(default(double), OnDefaultValueChanged)); + + public double? DefaultValue + { + get { return (double?) GetValue(DefaultValueProperty); } + set { SetValue(DefaultValueProperty, value); } + } + + private static void OnDefaultValueChanged(DependencyObject source, DependencyPropertyChangedEventArgs args) + { + ((UpDownBase) source).OnDefaultValueChanged((double) args.OldValue, (double) args.NewValue); + } + + private void OnDefaultValueChanged(double oldValue, double newValue) + { + if (IsInitialized && string.IsNullOrEmpty(Text)) + SyncTextAndValue(true, Text); + } + + #endregion //DefaultValue + + #region AllowInputSpecialValues + + private static readonly DependencyProperty AllowInputSpecialValuesProperty = + DependencyProperty.Register("AllowInputSpecialValues", typeof(AllowedSpecialValues), typeof(UpDownBase), + new UIPropertyMetadata(AllowedSpecialValues.None)); + + private AllowedSpecialValues AllowInputSpecialValues + { + get { return (AllowedSpecialValues) GetValue(AllowInputSpecialValuesProperty); } + set { SetValue(AllowInputSpecialValuesProperty, value); } + } + + #endregion //AllowInputSpecialValues + + #region ParsingNumberStyle + + public static readonly DependencyProperty ParsingNumberStyleProperty = + DependencyProperty.Register("ParsingNumberStyle", typeof(NumberStyles), typeof(UpDownBase), + new UIPropertyMetadata(NumberStyles.Any)); + + public NumberStyles ParsingNumberStyle + { + get { return (NumberStyles) GetValue(ParsingNumberStyleProperty); } + set { SetValue(ParsingNumberStyleProperty, value); } + } + + #endregion + + #region Value + + public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double?), + typeof(UpDownBase), + new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, + OnValueChanged, OnCoerceValue, false, UpdateSourceTrigger.PropertyChanged)); + + public double? Value + { + get { return (double?) GetValue(ValueProperty); } + set { SetValue(ValueProperty, value); } + } + + private static object OnCoerceValue(DependencyObject o, object basevalue) + { + return ((UpDownBase) o).OnCoerceValue(basevalue); + } + + protected virtual object OnCoerceValue(object newValue) + { + return newValue; + } + + private static void OnValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) + { + var upDownBase = o as UpDownBase; + if (upDownBase != null) + upDownBase.OnValueChanged((double) e.OldValue, (double) e.NewValue); + } + + protected virtual void OnValueChanged(double oldValue, double newValue) + { + if (IsInitialized) + SyncTextAndValue(false, null); + + SetValidSpinDirection(); + + var args = new RoutedPropertyChangedEventArgs(oldValue, newValue); + args.RoutedEvent = ValueChangedEvent; + RaiseEvent(args); + } + + #endregion //Value + + #endregion //Properties + + #region Base Class Overrides + + protected override void OnAccessKey(AccessKeyEventArgs e) + { + if (TextBox != null) + TextBox.Focus(); + + base.OnAccessKey(e); + } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + TextBox = GetTemplateChild(PartTextBox) as TextBox; + if (TextBox != null) + { + if (string.IsNullOrEmpty(Text)) + TextBox.Text = "0.0"; + else + TextBox.Text = Text; + + TextBox.LostFocus += TextBox_LostFocus; + TextBox.TextChanged += TextBox_TextChanged; + } + + if (Spinner != null) + Spinner.Spin -= OnSpinnerSpin; + + Spinner = GetTemplateChild(PartSpinner) as Spinner; + + if (Spinner != null) + Spinner.Spin += OnSpinnerSpin; + + SetValidSpinDirection(); + } + + protected override void OnGotFocus(RoutedEventArgs e) + { + if (TextBox != null) + TextBox.Focus(); + } + + protected override void OnPreviewKeyDown(KeyEventArgs e) + { + switch (e.Key) + { + case Key.Up: + { + if (AllowSpin && !IsReadOnly) + DoIncrement(); + e.Handled = true; + break; + } + case Key.Down: + { + if (AllowSpin && !IsReadOnly) + DoDecrement(); + e.Handled = true; + break; + } + } + } + + protected override void OnKeyDown(KeyEventArgs e) + { + switch (e.Key) + { + case Key.Enter: + { + var commitSuccess = CommitInput(); + e.Handled = !commitSuccess; + break; + } + } + } + + protected override void OnMouseWheel(MouseWheelEventArgs e) + { + base.OnMouseWheel(e); + + if (!e.Handled && AllowSpin && !IsReadOnly && TextBox.IsFocused) + { + if (e.Delta < 0) + DoDecrement(); + else if (0 < e.Delta) + DoIncrement(); + + e.Handled = true; + } + } + + protected void OnTextChanged(string oldValue, string newValue) + { + if (IsInitialized) + SyncTextAndValue(true, Text); + } + + protected void OnCultureInfoChanged(CultureInfo oldValue, CultureInfo newValue) + { + if (IsInitialized) + SyncTextAndValue(false, null); + } + + protected void OnReadOnlyChanged(bool oldValue, bool newValue) + { + SetValidSpinDirection(); + } + + public void OnSpin(SpinEventArgs e) + { + if (e == null) + throw new ArgumentNullException("e"); + + if (e.Direction == SpinDirection.Increase) + DoIncrement(); + else + DoDecrement(); + } + + #endregion + + #region Events + + public event InputValidationErrorEventHandler InputValidationError; + + #region ValueChanged Event + + public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent("ValueChanged", + RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler), typeof(UpDownBase)); + + public event RoutedPropertyChangedEventHandler ValueChanged + { + add { AddHandler(ValueChangedEvent, value); } + remove { RemoveHandler(ValueChangedEvent, value); } + } + + #endregion + + #endregion //Events + + #region Methods + + private void DoDecrement() + { + if (Spinner == null) + OnDecrement(); + } + + private void DoIncrement() + { + if (Spinner == null) + OnIncrement(); + } + + private void TextBox_TextChanged(object sender, TextChangedEventArgs e) + { + try + { + _isTextChangedFromUi = true; + Text = ((TextBox) sender).Text; + } + finally + { + _isTextChangedFromUi = false; + } + } + + private void TextBox_LostFocus(object sender, RoutedEventArgs e) + { + CommitInput(); + } + + private void RaiseInputValidationError(Exception e) + { + if (InputValidationError != null) + { + var args = new InputValidationErrorEventArgs(e); + InputValidationError(this, args); + if (args.ThrowException) + throw args.Exception; + } + } + + public bool CommitInput() + { + return SyncTextAndValue(true, Text); + } + + protected bool SyncTextAndValue(bool updateValueFromText, string text) + { + if (_isSyncingTextAndValueProperties) + return true; + + _isSyncingTextAndValueProperties = true; + var parsedTextIsValid = true; + try + { + if (updateValueFromText) + if (string.IsNullOrEmpty(text)) + Value = DefaultValue; + else + try + { + Value = ConvertTextToValue(text); + } + catch (Exception e) + { + parsedTextIsValid = false; + + // From the UI, just allow any input. + if (!_isTextChangedFromUi) + RaiseInputValidationError(e); + } + + // Do not touch the ongoing text input from user. + if (!_isTextChangedFromUi) + { + // Don't replace the empty Text with the non-empty representation of DefaultValue. + var shouldKeepEmpty = string.IsNullOrEmpty(Text) && Equals(Value, DefaultValue); + if (!shouldKeepEmpty) + Text = ConvertValueToText(); + + // Sync Text and textBox + if (TextBox != null) + if (string.IsNullOrEmpty(Text)) + TextBox.Text = "0.0"; + else + TextBox.Text = Text; + } + + if (_isTextChangedFromUi && !parsedTextIsValid) + { + //// Text input was made from the user and the text + //// repesents an invalid value. Disable the spinner + //// in this case. + if (Spinner != null) + Spinner.ValidSpinDirection = ValidSpinDirections.None; + } + else + { + SetValidSpinDirection(); + } + } + finally + { + _isSyncingTextAndValueProperties = false; + } + return parsedTextIsValid; + } + + protected static decimal ParsePercent(string text, IFormatProvider cultureInfo) + { + var info = NumberFormatInfo.GetInstance(cultureInfo); + + text = text.Replace(info.PercentSymbol, null); + + var result = decimal.Parse(text, NumberStyles.Any, info); + result = result/100; + + return result; + } + + #endregion + + #region Abstract + + protected abstract double? ConvertTextToValue(string text); + protected abstract string ConvertValueToText(); + protected abstract void OnIncrement(); + protected abstract void OnDecrement(); + protected abstract void SetValidSpinDirection(); + + #endregion + } +} \ No newline at end of file diff --git a/Artemis/ColorBox/Utils/ColorHelper.cs b/Artemis/ColorBox/Utils/ColorHelper.cs new file mode 100644 index 000000000..7e6e708a1 --- /dev/null +++ b/Artemis/ColorBox/Utils/ColorHelper.cs @@ -0,0 +1,209 @@ +/***************** NCore Softwares Pvt. Ltd., India ************************** + + ColorBox + + Copyright (C) 2013 NCore Softwares Pvt. Ltd. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://colorbox.codeplex.com/license + +***********************************************************************************/ + +using System; +using System.Globalization; +using System.Windows.Media; + +namespace ColorBox +{ + internal static class ColorHelper + { + private static readonly char[] HexArray = + { + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', + 'E', 'F' + }; + + public static string MakeValidColorString(string S) + { + var s = S; + + for (var i = 0; i < s.Length; i++) + { + var c = s[i]; + + if (!((c >= 'a') && (c <= 'f')) && !((c >= 'A') && (c <= 'F')) && !((c >= '0') && (c <= '9'))) + { + s = s.Remove(i, 1); + i--; + } + } + + if (s.Length > 8) s = s.Substring(0, 8); + + while ((s.Length <= 8) && (s.Length != 3) && (s.Length != 4) && (s.Length != 6) && (s.Length != 8)) + s = s + "0"; + + return s; + } + + public static Color ColorFromString(string S) + { + var s = MakeValidColorString(S); + + byte a = 255; + byte r = 0; + byte g = 0; + byte b = 0; + + if (s.Length == 3) + { + r = byte.Parse(s.Substring(0, 1) + s.Substring(0, 1), NumberStyles.HexNumber); + g = byte.Parse(s.Substring(1, 1) + s.Substring(1, 1), NumberStyles.HexNumber); + b = byte.Parse(s.Substring(2, 1) + s.Substring(2, 1), NumberStyles.HexNumber); + } + + if (s.Length == 4) + { + a = byte.Parse(s.Substring(0, 1) + s.Substring(0, 1), NumberStyles.HexNumber); + r = byte.Parse(s.Substring(1, 1) + s.Substring(1, 1), NumberStyles.HexNumber); + g = byte.Parse(s.Substring(2, 1) + s.Substring(2, 1), NumberStyles.HexNumber); + b = byte.Parse(s.Substring(3, 1) + s.Substring(3, 1), NumberStyles.HexNumber); + } + + if (s.Length == 6) + { + r = byte.Parse(s.Substring(0, 2), NumberStyles.HexNumber); + g = byte.Parse(s.Substring(1, 2), NumberStyles.HexNumber); + b = byte.Parse(s.Substring(2, 2), NumberStyles.HexNumber); + } + + if (s.Length == 8) + { + a = byte.Parse(s.Substring(0, 2), NumberStyles.HexNumber); + r = byte.Parse(s.Substring(1, 2), NumberStyles.HexNumber); + g = byte.Parse(s.Substring(2, 2), NumberStyles.HexNumber); + b = byte.Parse(s.Substring(3, 2), NumberStyles.HexNumber); + } + + return Color.FromArgb(a, r, g, b); + } + + public static string StringFromColor(Color c) + { + var bytes = new byte[4] {c.A, c.R, c.G, c.B}; + + var chars = new char[bytes.Length*2]; + + for (var i = 0; i < bytes.Length; i++) + { + int b = bytes[i]; + chars[i*2] = HexArray[b >> 4]; + chars[i*2 + 1] = HexArray[b & 0xF]; + } + + return new string(chars); + } + + public static Color ColorFromHsb(double H, double S, double b) + { + double red = 0.0, green = 0.0, blue = 0.0; + + if (S == 0.0) + { + red = green = blue = b; + } + else + { + var h = H*360; + while (h >= 360.0) + h -= 360.0; + + h = h/60.0; + var i = (int) h; + + var f = h - i; + var r = b*(1.0 - S); + var s = b*(1.0 - S*f); + var t = b*(1.0 - S*(1.0 - f)); + + switch (i) + { + case 0: + red = b; + green = t; + blue = r; + break; + case 1: + red = s; + green = b; + blue = r; + break; + case 2: + red = r; + green = b; + blue = t; + break; + case 3: + red = r; + green = s; + blue = b; + break; + case 4: + red = t; + green = r; + blue = b; + break; + case 5: + red = b; + green = r; + blue = s; + break; + } + } + + byte iRed = (byte) (red*255.0), iGreen = (byte) (green*255.0), iBlue = (byte) (blue*255.0); + return Color.FromRgb(iRed, iGreen, iBlue); + } + + public static void HsbFromColor(Color c, ref double h, ref double s, ref double b) + { + var red = c.R; + var green = c.G; + var blue = c.B; + + int imax = red, imin = red; + + if (green > imax) imax = green; + else if (green < imin) imin = green; + if (blue > imax) imax = blue; + else if (blue < imin) imin = blue; + double max = imax/255.0, min = imin/255.0; + + var value = max; + var saturation = max > 0 ? (max - min)/max : 0.0; + double hue = 0; + + if (imax > imin) + { + var f = 1.0/((max - min)*255.0); + hue = imax == red + ? 0.0 + f*(green - blue) + : imax == green ? 2.0 + f*(blue - red) : 4.0 + f*(red - green); + hue = hue*60.0; + if (hue < 0.0) + hue += 360.0; + } + + h = hue/360; + s = saturation; + b = value; + } + + public static Color ColorFromAhsb(double a, double h, double s, double b) + { + var r = ColorFromHsb(h, s, b); + r.A = (byte) Math.Round(a*255); + return r; + } + } +} \ No newline at end of file diff --git a/Artemis/ColorBox/Utils/InputValidationErrorEventArgs .cs b/Artemis/ColorBox/Utils/InputValidationErrorEventArgs .cs new file mode 100644 index 000000000..c657d7122 --- /dev/null +++ b/Artemis/ColorBox/Utils/InputValidationErrorEventArgs .cs @@ -0,0 +1,41 @@ +/************************************************************************************* + + Extended WPF Toolkit + + Copyright (C) 2007-2013 Xceed Software Inc. + + This program is provided to you under the terms of the Microsoft Public + License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license + + For more features, controls, and fast professional support, + pick up the Plus Edition at http://xceed.com/wpf_toolkit + + Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids + + ***********************************************************************************/ + +using System; + +namespace ColorBox +{ + public delegate void InputValidationErrorEventHandler(object sender, InputValidationErrorEventArgs e); + + public class InputValidationErrorEventArgs : EventArgs + { + public InputValidationErrorEventArgs(Exception e) + { + Exception = e; + } + + + public Exception Exception { get; private set; } + + public bool ThrowException { get; set; } + } + + internal interface IValidateInput + { + event InputValidationErrorEventHandler InputValidationError; + bool CommitInput(); + } +} \ No newline at end of file diff --git a/Artemis/ColorBox/Utils/TextBoxBehavior.cs b/Artemis/ColorBox/Utils/TextBoxBehavior.cs new file mode 100644 index 000000000..63e58332e --- /dev/null +++ b/Artemis/ColorBox/Utils/TextBoxBehavior.cs @@ -0,0 +1,61 @@ +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; + +namespace ColorBox +{ + public class TextBoxBehavior + { + public static readonly DependencyProperty SelectAllTextOnFocusProperty = + DependencyProperty.RegisterAttached( + "SelectAllTextOnFocus", + typeof(bool), + typeof(TextBoxBehavior), + new UIPropertyMetadata(false, OnSelectAllTextOnFocusChanged)); + + public static bool GetSelectAllTextOnFocus(TextBox textBox) + { + return (bool) textBox.GetValue(SelectAllTextOnFocusProperty); + } + + public static void SetSelectAllTextOnFocus(TextBox textBox, bool value) + { + textBox.SetValue(SelectAllTextOnFocusProperty, value); + } + + private static void OnSelectAllTextOnFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var textBox = d as TextBox; + if (textBox == null) return; + + if (e.NewValue is bool == false) return; + + if ((bool) e.NewValue) + { + textBox.GotFocus += SelectAll; + textBox.PreviewMouseDown += IgnoreMouseButton; + } + else + { + textBox.GotFocus -= SelectAll; + textBox.PreviewMouseDown -= IgnoreMouseButton; + } + } + + private static void SelectAll(object sender, RoutedEventArgs e) + { + var textBox = e.OriginalSource as TextBox; + if (textBox == null) return; + textBox.SelectAll(); + } + + private static void IgnoreMouseButton(object sender, MouseButtonEventArgs e) + { + var textBox = sender as TextBox; + if ((textBox == null) || textBox.IsKeyboardFocusWithin) return; + + e.Handled = true; + textBox.Focus(); + } + } +} \ No newline at end of file