More GUI improvements. Implemented attributes instead of dumb maps. Config loading and saving is done. Need to add some stuff around that.

This commit is contained in:
jrhodnik 2019-05-27 16:13:50 -04:00
parent a9e5e14c9d
commit 99b56d5ec0
19 changed files with 404 additions and 103 deletions

View File

@ -1,31 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VDash.Overlay.Config;
namespace VDash
{
public class ConfigManager
{
public string ConfigLocation { get; private set; }
public ConfigManager()
{
ConfigLocation = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.None) + @"\VRDash\DefaultProfile.json";
}
/// <summary>
/// Saves config to ConfigLocation
/// </summary>
public void SaveConfig()
{
}
}
public class Profile
{
public List<IOverlayConfig> OverlayConfigs { get; private set; }
}
}

View File

@ -0,0 +1,45 @@
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
// ReSharper disable once CheckNamespace
namespace JsonNet.PrivateSettersContractResolvers
{
public class PrivateSetterContractResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var jProperty = base.CreateProperty(member, memberSerialization);
if (jProperty.Writable)
return jProperty;
jProperty.Writable = member.IsPropertyWithSetter();
return jProperty;
}
}
public class PrivateSetterCamelCasePropertyNamesContractResolver : CamelCasePropertyNamesContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var jProperty = base.CreateProperty(member, memberSerialization);
if (jProperty.Writable)
return jProperty;
jProperty.Writable = member.IsPropertyWithSetter();
return jProperty;
}
}
internal static class MemberInfoExtensions
{
internal static bool IsPropertyWithSetter(this MemberInfo member)
{
var property = member as PropertyInfo;
return property?.GetSetMethod(true) != null;
}
}
}

92
VDash/Logger.cs Normal file
View File

@ -0,0 +1,92 @@
using log4net;
using log4net.Appender;
using log4net.Core;
using log4net.Layout;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VDash
{
public class Logger
{
public static void Setup()
{
var configLoc = ProfileManager.ConfigDirectory + @"\Logs\VRDash.log";
if (!Directory.Exists(Path.GetDirectoryName(configLoc)))
{
Directory.CreateDirectory(Path.GetDirectoryName(configLoc));
}
log4net.Repository.Hierarchy.Hierarchy hierarchy = (log4net.Repository.Hierarchy.Hierarchy)LogManager.GetRepository();
PatternLayout patternLayout = new PatternLayout();
patternLayout.ConversionPattern = "%date [%thread] %level %logger - %message%newline%exception";
patternLayout.ActivateOptions();
hierarchy.Root.RemoveAllAppenders();
#region File Appender
RollingFileAppender roller = new RollingFileAppender();
roller.AppendToFile = true;
roller.File = configLoc;
roller.Layout = patternLayout;
roller.MaxSizeRollBackups = 10;
roller.MaximumFileSize = "10MB";
roller.RollingStyle = RollingFileAppender.RollingMode.Size;
roller.StaticLogFileName = true;
roller.ActivateOptions();
hierarchy.Root.AddAppender(roller);
#endregion
//MemoryAppender memory = new MemoryAppender();
//memory.ActivateOptions();
//hierarchy.Root.AddAppender(memory);
ColoredConsoleAppender coloredConsoleAppender = new ColoredConsoleAppender();
coloredConsoleAppender.AddMapping(new ColoredConsoleAppender.LevelColors()
{
Level = Level.Fatal,
ForeColor = ColoredConsoleAppender.Colors.White | ColoredConsoleAppender.Colors.HighIntensity,
BackColor = ColoredConsoleAppender.Colors.Red | ColoredConsoleAppender.Colors.HighIntensity
});
coloredConsoleAppender.AddMapping(new ColoredConsoleAppender.LevelColors()
{
Level = Level.Error,
ForeColor = ColoredConsoleAppender.Colors.Red | ColoredConsoleAppender.Colors.HighIntensity
});
coloredConsoleAppender.AddMapping(new ColoredConsoleAppender.LevelColors()
{
Level = Level.Warn,
ForeColor = ColoredConsoleAppender.Colors.Yellow
});
coloredConsoleAppender.AddMapping(new ColoredConsoleAppender.LevelColors()
{
Level = Level.Info,
ForeColor = ColoredConsoleAppender.Colors.Cyan
});
coloredConsoleAppender.AddMapping(new ColoredConsoleAppender.LevelColors()
{
Level = Level.Debug,
ForeColor = ColoredConsoleAppender.Colors.White
});
coloredConsoleAppender.Layout = patternLayout;
coloredConsoleAppender.ActivateOptions();
hierarchy.Root.AddAppender(coloredConsoleAppender);
hierarchy.Root.Level = Level.Debug;
hierarchy.Configured = true;
//BasicConfigurator.Configure(hierarchy);
}
}
public static class LoggerExtensions
{
public static ILog GetLogger(this object instance)
{
return LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
}
}
}

View File

@ -21,9 +21,8 @@
</Grid.RowDefinitions>
<ToolBar Grid.Row="0">
<Button x:Name="btnAdd" Click="btnAdd_Click">Add</Button>
<Button x:Name="btnEdit">Edit</Button>
<Button x:Name="btnDisable">Disable</Button>
<Button x:Name="btnRemove" Click="btnRemove_Click">Remove</Button>
<Button x:Name="btnLoad" Click="btnLoad_Click">Load...</Button>
</ToolBar>
<ListView x:Name="lvOverlays" Grid.Row="1" SelectionChanged="lvOverlays_SelectionChanged">

View File

@ -1,4 +1,5 @@
using System;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
@ -26,15 +27,12 @@ namespace VDash
public partial class MainWindow : Window
{
public static OverlayManager OverlayManager = new OverlayManager();
public static List<EditorMap> EditorMapping = new List<EditorMap>()
{
new EditorMap(typeof(MonitorOverlay), typeof(UI.MonitorOverlayEditor)),
new EditorMap(typeof(WindowOverlay), typeof(UI.WindowOverlayEditor))
};
public static ProfileManager ProfileManager = new ProfileManager();
List<OverlayEditor> overlayEditors = new List<OverlayEditor>();
public MainWindow()
{
Logger.Setup();
this.GetLogger().Info("VDash is starting up...");
InitializeComponent();
//Connect to VR runtime...
@ -51,6 +49,20 @@ namespace VDash
lvOverlays.ItemsSource = OverlayManager.Overlays;
KeyDown += (s, e) =>
{
if(e.Key == Key.F5)
{
ProfileManager.SaveProfile();
}
if(e.Key == Key.F6 || e.Key == Key.P)
{
var profile = ProfileManager.LoadProfile();
LoadProfile(profile);
}
};
#region Debug
@ -80,15 +92,44 @@ namespace VDash
#endregion
}
private void LoadProfile(Profile profile)
{
//Dispose of all overlays and clear list.
foreach (var overlay in OverlayManager.Overlays)
{
overlay.Overlay.Dispose();
}
OverlayManager.Overlays.Clear();
var configs = profile.OverlayConfigs;
foreach (var config in configs)
{
//Get type of overlay based on config type
var attrs = OverlayInfo.GetOverlayInfos();
var overlayInfo = attrs.Single(x => x.Info.ConfigType == config.GetType());
Type overlayType = overlayInfo.OverlayType;
//Create overlay
IOverlay overlay = (IOverlay)Activator.CreateInstance(overlayType, new object[] { config });
overlay.Create();
UI.IOverlayEditor editor = (UI.IOverlayEditor)Activator.CreateInstance(overlayInfo.Info.EditorType, new object[] { overlay.OverlayConfig });
OverlayEditorInfo overlayEditor = new OverlayEditorInfo(new UI.OverlayEditor(editor), overlay);
OverlayManager.Overlays.Add(overlayEditor);
}
}
private void btnAdd_Click(object sender, RoutedEventArgs e)
{
Window w = new Window();
var uc = new UI.CreateNewOverlay();
uc.Created += (snd, overlay) => {
w.Close();
UI.IOverlayEditor editor = (UI.IOverlayEditor)Activator.CreateInstance(EditorMapping.Single(x => x.OverlayType == overlay.GetType()).EditorType, new object[] { overlay.OverlayConfig });
OverlayEditor overlayEditor = new OverlayEditor(new UI.OverlayEditor(editor), overlay);
overlayEditors.Add(overlayEditor);
var attrs = OverlayInfo.GetOverlayInfos();
var overlayInfo = attrs.Single(x => x.OverlayType == overlay.GetType());
UI.IOverlayEditor editor = (UI.IOverlayEditor)Activator.CreateInstance(overlayInfo.Info.EditorType, new object[] { overlay.OverlayConfig });
OverlayEditorInfo overlayEditor = new OverlayEditorInfo(new UI.OverlayEditor(editor), overlay);
OverlayManager.Overlays.Add(overlayEditor);
};
w.Content = uc;
w.Width = 500;
@ -100,31 +141,28 @@ namespace VDash
private void btnRemove_Click(object sender, RoutedEventArgs e)
{
if(lvOverlays.SelectedItem == null) { return; }
IOverlay overlay = (IOverlay)lvOverlays.SelectedItem;
overlay.Dispose();
OverlayManager.Overlays.Remove(overlay);
overlayEditors.Remove(overlayEditors.Single(x => x.Overlay == overlay));
OverlayEditorInfo overlayEditor = (OverlayEditorInfo)lvOverlays.SelectedItem;
overlayEditor.Overlay.Dispose();
OverlayManager.Overlays.Remove(overlayEditor);
if (bdrContent.Child == overlayEditor.Editor)
{
bdrContent.Child = null;
}
}
private void lvOverlays_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (lvOverlays.SelectedItem == null) { return; }
IOverlay overlay = (IOverlay)lvOverlays.SelectedItem;
OverlayEditorInfo overlay = (OverlayEditorInfo)lvOverlays.SelectedItem;
bdrContent.Child = (UserControl)overlayEditors.Single(x => x.Overlay == overlay).Editor;
bdrContent.Child = (UserControl)overlay.Editor;
}
}
public class OverlayEditor
{
public OverlayEditor(IOverlayEditor editor, IOverlay overlay)
private void btnLoad_Click(object sender, RoutedEventArgs e)
{
Editor = editor;
Overlay = overlay;
var profile = ProfileManager.LoadProfile();
LoadProfile(profile);
}
public UI.IOverlayEditor Editor { get; private set; }
public IOverlay Overlay { get; private set; }
}
public class EditorMap

View File

@ -8,7 +8,7 @@ using VDash.Utilities;
namespace VDash.Overlay.Actions
{
[OverlayActionInfo("Minize Window")]
public class MinimizeWIndowAction : IWindowAction
public class MinimizeWindowAction : IWindowAction
{
public bool Enabled { get; set; } = true;

View File

@ -11,7 +11,10 @@ namespace VDash.Overlay.Config
public event EventHandler WidthUpdated;
public string Name { get; set; }
public string Key { get; set; }
public string MonitorName { get; set; }
public string MonitorName {
get;
set;
}
float m_Width = 2.5f;
public float OverlayWidth
{

View File

@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using VDash.Overlay.Actions;
using VDash.Overlay.Config;
using System.Linq;
namespace VDash.Overlay
{
@ -22,4 +24,53 @@ namespace VDash.Overlay
int CurrentFPS { get; }
}
public class OverlayInfo : System.Attribute
{
public OverlayInfo(string description, Type configType, Type editorType)
{
Description = description;
ConfigType = configType;
EditorType = editorType;
}
public string Description { get; private set; }
public Type ConfigType { get; private set; }
public Type EditorType { get; private set; }
public static IEnumerable<Type> GetTypesWithAttribute()
{
var assembly = Assembly.GetExecutingAssembly();
foreach (Type type in assembly.GetTypes())
{
if (type.GetCustomAttributes(typeof(OverlayInfo), true).Length > 0)
{
yield return type;
}
}
}
public class OverlayAttributeInfo
{
public OverlayAttributeInfo(Type type, OverlayInfo info)
{
OverlayType = type;
Info = info;
}
public Type OverlayType { get; private set; }
public OverlayInfo Info { get; private set; }
}
public static OverlayAttributeInfo[] GetOverlayInfos()
{
List<OverlayAttributeInfo> infos = new List<OverlayAttributeInfo>();
var attrs = GetTypesWithAttribute();
foreach(var attr in attrs)
{
OverlayInfo thingInfo = (OverlayInfo)attr.GetCustomAttribute(typeof(OverlayInfo), true);
infos.Add(new OverlayAttributeInfo(attr, thingInfo));
}
return infos.ToArray();
}
}
}

View File

@ -18,9 +18,11 @@ using VDash.WindowSelectors;
using System.Linq;
using static VDash.Utilities.User32;
using VDash.Overlay.Config;
using VDash.UI;
namespace VDash.Overlay
{
[OverlayInfo("Monitor Overlay", typeof(MonitorOverlayConfig), typeof(MonitorOverlayEditor))]
public class MonitorOverlay : IOverlay
{

View File

@ -17,9 +17,11 @@ using VDash.Utilities;
using VDash.WindowSelectors;
using System.Linq;
using VDash.Overlay.Config;
using VDash.UI;
namespace VDash.Overlay
{
[OverlayInfo("Window Overlay", typeof(WindowOverlayConfig), typeof(WindowOverlayEditor))]
public class WindowOverlay : IOverlay
{
public event EventHandler OverlayShown;

View File

@ -7,11 +7,31 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VDash.Overlay;
using VDash.UI;
namespace VDash
{
public class OverlayManager
{
public ObservableCollection<IOverlay> Overlays { get; internal set; } = new ObservableCollection<IOverlay>();
public ObservableCollection<OverlayEditorInfo> Overlays { get; internal set; } = new ObservableCollection<OverlayEditorInfo>();
}
public class OverlayEditorInfo
{
public OverlayEditorInfo(IOverlayEditor editor, IOverlay overlay)
{
Editor = editor;
Overlay = overlay;
}
public UI.IOverlayEditor Editor { get; private set; }
public IOverlay Overlay { get; private set; }
public override string ToString()
{
return Overlay.ToString();
}
}
}

73
VDash/ProfileManager.cs Normal file
View File

@ -0,0 +1,73 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VDash.Overlay.Config;
namespace VDash
{
public class ProfileManager
{
public static string ConfigDirectory { get { return Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments, Environment.SpecialFolderOption.None) + @"\VRDash\"; } }
public static string ConfigLocation { get { return ConfigDirectory + "DefaultProfile.vdc"; } }
JsonSerializerSettings m_Settings = new JsonSerializerSettings()
{
TypeNameHandling = TypeNameHandling.All,
Formatting = Formatting.Indented,
ContractResolver = new JsonNet.PrivateSettersContractResolvers.PrivateSetterContractResolver()
};
public ProfileManager()
{
}
public void SaveProfile()
{
var path = Path.GetDirectoryName(ConfigLocation);
//Make sure directory tree exists
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
SaveProfile(ConfigLocation);
}
/// <summary>
/// Saves config to ConfigLocation
/// </summary>
public void SaveProfile(string location)
{
IOverlayConfig[] selection = MainWindow.OverlayManager.Overlays.Select(x => x.Overlay.OverlayConfig).ToArray();
var profile = new Profile(selection);
var json = JsonConvert.SerializeObject(profile, m_Settings);
File.WriteAllText(location, json);
}
public Profile LoadProfile()
{
return LoadProfile(ConfigLocation);
}
public Profile LoadProfile(string location)
{
var json = File.ReadAllText(location);
var profile = JsonConvert.DeserializeObject<Profile>(json, m_Settings);
return profile;
}
}
public class Profile
{
public Profile(IOverlayConfig[] overlayConfigs)
{
OverlayConfigs = overlayConfigs;
}
public Profile() { }
public IOverlayConfig[] OverlayConfigs { get; private set; }
}
}

View File

@ -13,6 +13,7 @@ using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VDash.Overlay;
using VDash.Overlay.Config;
namespace VDash.UI
{
@ -24,15 +25,25 @@ namespace VDash.UI
public delegate void CreatedEventHandler(UserControl sender, IOverlay created);
public event CreatedEventHandler Created;
public OverlayTypeWrapper[] EligibleOverlays { get; private set; } = {
new OverlayTypeWrapper("Window Overlay", typeof(WindowOverlay), new OverlayEditor(new WindowOverlayEditor())),
new OverlayTypeWrapper("Monitor Overlay", typeof(MonitorOverlay), new OverlayEditor(new MonitorOverlayEditor()))
};
public List<OverlayTypeWrapper> EligibleOverlays { get; private set; } = new List<OverlayTypeWrapper>();
public CreateNewOverlay()
{
InitializeComponent();
DataContext = this;
foreach (var info in OverlayInfo.GetOverlayInfos())
{
var newWrapper = new OverlayTypeWrapper(info);
//Add "Bring to front" for window overlays. Conveneience, my dude.
if(info.OverlayType == typeof(WindowOverlay))
{
((WindowOverlayConfig)newWrapper.Config).OverlayShownActions.Add(new Overlay.Actions.BringWindowToFrontAction());
}
EligibleOverlays.Add(newWrapper);
}
}
private void cbOverlayType_SelectionChanged(object sender, SelectionChangedEventArgs e)
@ -58,16 +69,16 @@ namespace VDash.UI
}
var wrapper = ((OverlayTypeWrapper)cbOverlayType.SelectedItem);
var config = wrapper.Editor.Config;
var config = wrapper.Config;
if (String.IsNullOrWhiteSpace(config.Key))
{
config.Key = RandomString(8, true);
}
IOverlay overlay = (IOverlay)Activator.CreateInstance(wrapper.OverlayType, new object[] { config });
IOverlay overlay = (IOverlay)Activator.CreateInstance(wrapper.OverlayInfo.OverlayType, new object[] { config });
overlay.Create();
MainWindow.OverlayManager.Overlays.Add(overlay);
//MainWindow.OverlayManager.Overlays.Add(overlay);
Created?.Invoke(this, overlay);
}
@ -92,24 +103,22 @@ namespace VDash.UI
public class OverlayTypeWrapper
{
public Type OverlayType { get; private set; }
public string FriendlyName { get; private set; }
public OverlayTypeWrapper(OverlayInfo.OverlayAttributeInfo overlayInfo)
{
OverlayInfo = overlayInfo;
Config = (IOverlayConfig)Activator.CreateInstance(OverlayInfo.Info.ConfigType);
Control = (UserControl)Activator.CreateInstance(OverlayInfo.Info.EditorType, new object[] { Config });
}
public OverlayInfo.OverlayAttributeInfo OverlayInfo { get; private set; }
public UserControl Control { get; private set; }
//this is a bit messy...
public IOverlayEditor Editor { get { return (IOverlayEditor)Control; } }
public OverlayTypeWrapper(string friendlyName, Type overlayType, UserControl control)
{
if (!typeof(IOverlay).IsAssignableFrom(overlayType))
{
throw new Exception("The type must be based on IOverlay.");
}
OverlayType = overlayType;
FriendlyName = friendlyName;
Control = control;
}
public IOverlayConfig Config { get; private set; }
public override string ToString()
{
return FriendlyName;
return OverlayInfo.Info.Description;
}
}
}

View File

@ -24,7 +24,7 @@
<TextBox x:Name="tbName" Grid.Row="0" Grid.Column="1" Margin="0,0,0,3" Text="{Binding Name}"/>
<ComboBox x:Name="cbMontitor" Grid.Row="1" Grid.Column="1" SelectionChanged="cbMontitor_SelectionChanged" SelectedIndex="0"></ComboBox>
<ComboBox x:Name="cbMontitor" Grid.Row="1" Grid.Column="1" SelectionChanged="cbMontitor_SelectionChanged"></ComboBox>
</Grid>
</UserControl>

View File

@ -23,7 +23,7 @@ namespace VDash.UI
public partial class MonitorOverlayEditor : UserControl,IOverlayEditor
{
public IOverlayConfig Config { get { return OverlayConfig; } }
public MonitorOverlayConfig OverlayConfig { get; set; } = new MonitorOverlayConfig();
public MonitorOverlayConfig OverlayConfig { get; set; }
public MonitorOverlayEditor(ref MonitorOverlayConfig config)
{
@ -32,16 +32,9 @@ namespace VDash.UI
DataContext = OverlayConfig;
var displays = GetDisplays();
cbMontitor.ItemsSource = displays;
cbMontitor.SelectedItem = displays.Single(x => x.MonitorInfo.DeviceName == OverlayConfig.MonitorName);
cbMontitor.SelectedItem = displays.SingleOrDefault(x => x.MonitorInfo.DeviceName == OverlayConfig.MonitorName);
}
public MonitorOverlayEditor()
{
InitializeComponent();
DataContext = OverlayConfig;
cbMontitor.ItemsSource = GetDisplays();
}
private void cbMontitor_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
OverlayConfig.MonitorName = ((DisplayInfo)cbMontitor.SelectedItem).MonitorInfo.DeviceName;

View File

@ -36,16 +36,16 @@ namespace VDash.UI
public IOverlayConfig Config { get { return OverlayConfig; } }
public WindowOverlayEditor()
{
InitializeComponent();
OverlayConfig = new WindowOverlayConfig();
OverlayConfig.OverlayShownActions.Add(new BringWindowToFrontAction(true));
DataContext = OverlayConfig;
//public WindowOverlayEditor()
//{
// InitializeComponent();
// OverlayConfig = new WindowOverlayConfig();
// OverlayConfig.OverlayShownActions.Add(new BringWindowToFrontAction(true));
// DataContext = OverlayConfig;
cbSelector.ItemsSource = Selectors;
SetupDropDown();
}
// cbSelector.ItemsSource = Selectors;
// SetupDropDown();
//}
public WindowOverlayEditor(ref WindowOverlayConfig config)
{

View File

@ -91,7 +91,9 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="ConfigManager.cs" />
<Compile Include="Logger.cs" />
<Compile Include="ProfileManager.cs" />
<Compile Include="JsonNet.PrivateSettersContractResolvers\PrivateSettersContractResolvers.cs" />
<Compile Include="OverlayManager.cs" />
<Compile Include="Overlay\Actions\BringWindowToFrontAction.cs" />
<Compile Include="Overlay\Actions\IOverlayAction.cs" />

View File

@ -1,4 +1,5 @@
using System;
using Newtonsoft.Json;
using System;
using System.Linq;
using System.Text.RegularExpressions;
using VDash.Utilities;
@ -12,6 +13,7 @@ namespace VDash.WindowSelectors
public string TitleFilter { get; set; } = "";
public TitleSearchType SearchType { get; set; } = TitleSearchType.Contains;
[JsonIgnore]
public WindowInfo Window
{
get

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="JsonNet.PrivateSettersContractResolvers.Source" version="0.1.0" targetFramework="net45" developmentDependency="true" />
<package id="log4net" version="2.0.8" targetFramework="net45" />
<package id="Newtonsoft.Json" version="12.0.2" targetFramework="net45" />
<package id="SharpDX" version="4.2.0" targetFramework="net45" />