Started implementing GUI.

This commit is contained in:
jrhodnik 2019-05-25 23:42:59 -04:00
parent 945c286fb2
commit 6f3c6fa75e
29 changed files with 751 additions and 97 deletions

12
VDash/ConfigManager.cs Normal file
View File

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VDash
{
class ConfigManager
{
}
}

View File

@ -7,9 +7,28 @@
mc:Ignorable="d" mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"> Title="MainWindow" Height="450" Width="800">
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.ColumnDefinitions>
<RowDefinition Height="20" /> <ColumnDefinition Width="250" />
<RowDefinition Height="*" /> <ColumnDefinition Width="*" />
</Grid.RowDefinitions> </Grid.ColumnDefinitions>
<Border Background="White" BorderBrush="Gainsboro" BorderThickness="1" Margin="5,0,0,5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</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>
</ToolBar>
<ListView x:Name="lvOverlays" Grid.Row="1">
</ListView>
</Grid>
</Border>
</Grid> </Grid>
</Window> </Window>

View File

@ -23,11 +23,12 @@ namespace VDash
/// </summary> /// </summary>
public partial class MainWindow : Window public partial class MainWindow : Window
{ {
public static OverlayManager OverlayManager = new OverlayManager();
public MainWindow() public MainWindow()
{ {
InitializeComponent(); InitializeComponent();
// Connect to VR runtime... //Connect to VR runtime...
EVRInitError initError = EVRInitError.None; EVRInitError initError = EVRInitError.None;
var ret = OpenVR.Init(ref initError, EVRApplicationType.VRApplication_Overlay); var ret = OpenVR.Init(ref initError, EVRApplicationType.VRApplication_Overlay);
@ -37,6 +38,10 @@ namespace VDash
throw new Exception($"Error connecting to VR: {initError.ToString()}"); throw new Exception($"Error connecting to VR: {initError.ToString()}");
} }
lvOverlays.ItemsSource = OverlayManager.Overlays;
#region Debug
//StartOverlayWindow("Discord"); //StartOverlayWindow("Discord");
@ -54,29 +59,34 @@ namespace VDash
//var bringWindow = new Overlay.Actions.BringWindowToFrontAction(true); //var bringWindow = new Overlay.Actions.BringWindowToFrontAction(true);
//obsoverlay.OverlayShownActions.Add(bringWindow); //obsoverlay.OverlayShownActions.Add(bringWindow);
var displays = User32.GetDisplays(); //var displays = User32.GetDisplays();
MonitorOverlay mo0 = new MonitorOverlay("left", "Left Monitor", displays[0]); //MonitorOverlay mo0 = new MonitorOverlay("left", "Left Monitor", displays[0]);
mo0.Create(); //mo0.Create();
MonitorOverlay mo1 = new MonitorOverlay("center", "Center Monitor", displays[1]); //MonitorOverlay mo1 = new MonitorOverlay("center", "Center Monitor", displays[1]);
mo1.Create(); //mo1.Create();
MonitorOverlay mo2= new MonitorOverlay("right", "Right Monitor", displays[2]); //MonitorOverlay mo2= new MonitorOverlay("right", "Right Monitor", displays[2]);
mo2.Create(); //mo2.Create();
#endregion
} }
private void btnAdd_Click(object sender, RoutedEventArgs e)
//This is just for debugging I swear
int count = 0;
IOverlay StartOverlayWindow(string windowFilter)
{ {
var ws = new WindowSelectors.FromWindowTitle(windowFilter, WindowSelectors.FromWindowTitle.TitleSearchType.Contains); Window w = new Window();
Overlay.WindowOverlay overlay = new Overlay.WindowOverlay($"ws{count}", "Loading...", ws, true); var uc = new UI.CreateNewOverlay();
overlay.Create(); uc.Created += (x, y) => { w.Close(); };
w.Content = uc;
w.Width = 500;
w.Height = 400;
w.SizeToContent = System.Windows.SizeToContent.Height;
w.Show();
}
var bringWindow = new Overlay.Actions.BringWindowToFrontAction(true); private void btnRemove_Click(object sender, RoutedEventArgs e)
overlay.OverlayShownActions.Add(bringWindow); {
count++; if(lvOverlays.SelectedItem == null) { return; }
return overlay; IOverlay overlay = (IOverlay)lvOverlays.SelectedItem;
overlay.Dispose();
OverlayManager.Overlays.Remove(overlay);
} }
} }
} }

View File

@ -32,7 +32,7 @@ namespace VDash.Overlay.Actions
} }
WindowOverlay overlay = (WindowOverlay)intOverlay; WindowOverlay overlay = (WindowOverlay)intOverlay;
IntPtr handle = overlay.Selector.GetWindowHandle(); IntPtr handle = overlay.Config.Selector.GetWindowHandle();
PreformAction(handle); PreformAction(handle);
} }

View File

@ -22,7 +22,7 @@ namespace VDash.Overlay.Actions
} }
WindowOverlay overlay = (WindowOverlay)intOverlay; WindowOverlay overlay = (WindowOverlay)intOverlay;
IntPtr handle = overlay.Selector.GetWindowHandle(); IntPtr handle = overlay.Config.Selector.GetWindowHandle();
PreformAction(handle); PreformAction(handle);
} }

View File

@ -29,7 +29,7 @@ namespace VDash.Overlay.Actions
} }
WindowOverlay overlay = (WindowOverlay)intOverlay; WindowOverlay overlay = (WindowOverlay)intOverlay;
IntPtr handle = overlay.Selector.GetWindowHandle(); IntPtr handle = overlay.Config.Selector.GetWindowHandle();
PreformAction(handle); PreformAction(handle);
} }

View File

@ -22,7 +22,7 @@ namespace VDash.Overlay.Actions
} }
WindowOverlay overlay = (WindowOverlay)intOverlay; WindowOverlay overlay = (WindowOverlay)intOverlay;
IntPtr handle = overlay.Selector.GetWindowHandle(); IntPtr handle = overlay.Config.Selector.GetWindowHandle();
PreformAction(handle); PreformAction(handle);
} }

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VDash.Overlay.Config
{
public interface IOverlayConfig
{
string Name { get; set; }
string Key { get; set; }
}
}

View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace VDash.Overlay.Config
{
public class MonitorOverlayConfig : IOverlayConfig
{
public string Name { get; set; }
public string Key { get; set; }
public string MonitorName { get; set; }
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VDash.WindowSelectors;
namespace VDash.Overlay.Config
{
public class WindowOverlayConfig : IOverlayConfig
{
public WindowOverlayConfig(string name, string key, IWindowSelector selector, bool updateDashboardName, bool destroyOnNoWindowFound)
{
Name = name;
Key = key;
Selector = selector;
UpdateDashboardName = updateDashboardName;
DestroyOnNoWindowFound = destroyOnNoWindowFound;
}
public WindowOverlayConfig() { }
public string Name { get; set; }
public string Key { get; set; }
public IWindowSelector Selector {get; set; }
public bool UpdateDashboardName { get; set; } = false;
public bool DestroyOnNoWindowFound { get; set; } = false;
}
}

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using VDash.Overlay.Actions; using VDash.Overlay.Actions;
using VDash.Overlay.Config;
namespace VDash.Overlay namespace VDash.Overlay
{ {
@ -13,8 +14,7 @@ namespace VDash.Overlay
List<IOverlayAction> OverlayHiddenActions { get; } List<IOverlayAction> OverlayHiddenActions { get; }
ulong OverlayHandle { get; } ulong OverlayHandle { get; }
string Name { get; } IOverlayConfig OverlayConfig { get; }
string Key { get; }
void Create(); void Create();
void Destroy(); void Destroy();
@ -22,5 +22,7 @@ namespace VDash.Overlay
float GetOverlayWidth(); float GetOverlayWidth();
void SetOverlayWidth(float width); void SetOverlayWidth(float width);
void SetOverlayName(string newName); void SetOverlayName(string newName);
int CurrentFPS { get; }
} }
} }

View File

@ -17,6 +17,7 @@ using VDash.Utilities;
using VDash.WindowSelectors; using VDash.WindowSelectors;
using System.Linq; using System.Linq;
using static VDash.Utilities.User32; using static VDash.Utilities.User32;
using VDash.Overlay.Config;
namespace VDash.Overlay namespace VDash.Overlay
{ {
@ -35,30 +36,29 @@ namespace VDash.Overlay
bool m_Created = false; bool m_Created = false;
bool m_Running = true; bool m_Running = true;
public DisplayInfo DisplayInfo { get; private set; } public DisplayInfo DisplayInfo { get
{
return User32.GetDisplays().Single(x => x.MonitorInfo.DeviceName == Config.MonitorName);
}
}
internal ulong m_OverlayHandle; internal ulong m_OverlayHandle;
public ulong OverlayHandle { get { return m_OverlayHandle; } } public ulong OverlayHandle { get { return m_OverlayHandle; } }
internal ulong m_ThumbnailIcon; internal ulong m_ThumbnailIcon;
public ulong ThumbnailIcon { get { return m_ThumbnailIcon; } } public ulong ThumbnailIcon { get { return m_ThumbnailIcon; } }
internal string m_Key;
public string Key { get { return m_Key; } }
internal string m_Name;
public string Name { get { return m_Name; } }
public List<IOverlayAction> OverlayShownActions { get; private set; } = new List<IOverlayAction>(); public List<IOverlayAction> OverlayShownActions { get; private set; } = new List<IOverlayAction>();
public List<IOverlayAction> OverlayHiddenActions { get; private set; } = new List<IOverlayAction>(); public List<IOverlayAction> OverlayHiddenActions { get; private set; } = new List<IOverlayAction>();
public IOverlayConfig OverlayConfig { get { return Config; } }
public MonitorOverlayConfig Config { get; set; }
char[] specialKeys = { '+', '^', '%', '~', '(', ')', '{', '}', '[', ']' }; char[] specialKeys = { '+', '^', '%', '~', '(', ')', '{', '}', '[', ']' };
public MonitorOverlay(string key, string name, DisplayInfo display) public MonitorOverlay(MonitorOverlayConfig config)
{ {
m_Key = key; Config = config;
m_Name = name;
DisplayInfo = display;
} }
@ -74,7 +74,7 @@ namespace VDash.Overlay
//Actually create the overlay //Actually create the overlay
var overlay = OpenVR.Overlay; var overlay = OpenVR.Overlay;
EVROverlayError err = overlay.CreateDashboardOverlay(m_Key, m_Name, ref m_OverlayHandle, ref m_ThumbnailIcon); EVROverlayError err = overlay.CreateDashboardOverlay(Config.Key, Config.Name, ref m_OverlayHandle, ref m_ThumbnailIcon);
if (err != EVROverlayError.None) if (err != EVROverlayError.None)
{ {
@ -352,7 +352,6 @@ namespace VDash.Overlay
int width = rect.right - rect.left; int width = rect.right - rect.left;
int height = rect.bottom - rect.top; int height = rect.bottom - rect.top;
//Make sure the coords are actually valid. Could be minimized or something.
if (width > 0 && height > 0) if (width > 0 && height > 0)
{ {
using (var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb)) using (var bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb))
@ -542,7 +541,6 @@ namespace VDash.Overlay
public void SetOverlayName(string newName) public void SetOverlayName(string newName)
{ {
OpenVR.Overlay.SetOverlayName(m_OverlayHandle, newName); OpenVR.Overlay.SetOverlayName(m_OverlayHandle, newName);
m_Name = newName;
} }
public float GetOverlayWidth() public float GetOverlayWidth()
@ -556,5 +554,10 @@ namespace VDash.Overlay
{ {
OpenVR.Overlay.SetOverlayWidthInMeters(m_OverlayHandle, width); OpenVR.Overlay.SetOverlayWidthInMeters(m_OverlayHandle, width);
} }
public override string ToString()
{
return Config.Name;
}
} }
} }

View File

@ -16,17 +16,14 @@ using VDash.Overlay.Actions;
using VDash.Utilities; using VDash.Utilities;
using VDash.WindowSelectors; using VDash.WindowSelectors;
using System.Linq; using System.Linq;
using VDash.Overlay.Config;
namespace VDash.Overlay namespace VDash.Overlay
{ {
public class WindowOverlay : IOverlay public class WindowOverlay : IOverlay
{ {
public event EventHandler OverlayShown; public event EventHandler OverlayShown;
public event EventHandler OverlayHidden; public event EventHandler OverlayHidden;
public bool UpdateDashboardName { get; set; } = false;
public bool DestroyOnNoWindowFound { get; set; } = false;
public int CurrentFPS { get; private set; } public int CurrentFPS { get; private set; }
private Task m_EventPumpTask = null; private Task m_EventPumpTask = null;
@ -40,27 +37,26 @@ namespace VDash.Overlay
public ulong OverlayHandle { get { return m_OverlayHandle; } } public ulong OverlayHandle { get { return m_OverlayHandle; } }
internal ulong m_ThumbnailIcon; internal ulong m_ThumbnailIcon;
public ulong ThumbnailIcon { get { return m_ThumbnailIcon; } } public ulong ThumbnailIcon { get { return m_ThumbnailIcon; } }
public IOverlayConfig OverlayConfig { get { return Config; } }
internal string m_Key; public WindowOverlayConfig Config { get; set; }
public string Key { get { return m_Key; } }
internal string m_Name; //internal string m_Key;
public string Name { get { return m_Name; } }
//internal string m_Name;
public IWindowSelector Selector { get; private set; } = null; //public IWindowSelector Selector { get; private set; } = null;
public List<IOverlayAction> OverlayShownActions { get; private set; } = new List<IOverlayAction>(); public List<IOverlayAction> OverlayShownActions { get; private set; } = new List<IOverlayAction>();
public List<IOverlayAction> OverlayHiddenActions { get; private set; } = new List<IOverlayAction>(); public List<IOverlayAction> OverlayHiddenActions { get; private set; } = new List<IOverlayAction>();
char[] specialKeys = { '+', '^', '%', '~', '(', ')', '{', '}', '[', ']' }; char[] specialKeys = { '+', '^', '%', '~', '(', ')', '{', '}', '[', ']' };
public WindowOverlay(string key, string name, IWindowSelector selector, bool updateDashboardName) public WindowOverlay(WindowOverlayConfig config)
{ {
m_Key = key; //Selector = selector;
m_Name = name; Config = config;
Selector = selector;
UpdateDashboardName = updateDashboardName;
} }
/// <summary> /// <summary>
@ -82,7 +78,7 @@ namespace VDash.Overlay
//Actually create the overlay //Actually create the overlay
var overlay = OpenVR.Overlay; var overlay = OpenVR.Overlay;
EVROverlayError err = overlay.CreateDashboardOverlay(m_Key, m_Name, ref m_OverlayHandle, ref m_ThumbnailIcon); EVROverlayError err = overlay.CreateDashboardOverlay(Config.Key, Config.Name, ref m_OverlayHandle, ref m_ThumbnailIcon);
if (err != EVROverlayError.None) if (err != EVROverlayError.None)
{ {
@ -161,21 +157,21 @@ namespace VDash.Overlay
while (m_Running) while (m_Running)
{ {
if (DestroyOnNoWindowFound) if (Config.DestroyOnNoWindowFound)
{ {
//Check to see if the window actually exists. Act accordingly. //Check to see if the window actually exists. Act accordingly.
if (!Selector.WindowExists()) if (!Config.Selector.WindowExists())
{ {
if (IsCreated()) if (IsCreated())
{ {
destroyInternal(); destroyInternal();
Console.WriteLine($"Destroyed {m_Key} because it's window does not exist."); Console.WriteLine($"Destroyed {Config.Key} because it's window does not exist.");
} }
Thread.Sleep(100); Thread.Sleep(100);
continue; continue;
} }
else if(Selector.WindowExists() && !m_Created && !m_Destroyed) else if(Config.Selector.WindowExists() && !m_Created && !m_Destroyed)
{ {
createInternal(); createInternal();
} }
@ -185,16 +181,16 @@ namespace VDash.Overlay
IntPtr windowHandle = IntPtr.Zero; IntPtr windowHandle = IntPtr.Zero;
try try
{ {
windowHandle = Selector.GetWindowHandle(); windowHandle = Config.Selector.GetWindowHandle();
} }
catch (WindowNotFoundException) catch (WindowNotFoundException)
{ {
} }
//Update the SteamVR dash name if necessary, only once a second. //Update the SteamVR dash name if necessary, only once a second.
if (Selector.WindowExists() && UpdateDashboardName && DateTime.Now.Subtract(lastNameCheck).TotalMilliseconds >= 1000) if (Config.Selector.WindowExists() && Config.UpdateDashboardName && DateTime.Now.Subtract(lastNameCheck).TotalMilliseconds >= 1000)
{ {
var window = Selector.GetWindowInfo(); var window = Config.Selector.GetWindowInfo();
if(GetOverlayName() != window.Title) if(GetOverlayName() != window.Title)
{ {
SetOverlayName(window.Title); SetOverlayName(window.Title);
@ -339,7 +335,7 @@ namespace VDash.Overlay
{ {
OverlayShown?.Invoke(this, new EventArgs()); OverlayShown?.Invoke(this, new EventArgs());
if (Selector.WindowExists()) if (Config.Selector.WindowExists())
{ {
foreach (var action in OverlayShownActions) foreach (var action in OverlayShownActions)
{ {
@ -352,7 +348,7 @@ namespace VDash.Overlay
{ {
OverlayHidden?.Invoke(this, new EventArgs()); OverlayHidden?.Invoke(this, new EventArgs());
if (Selector.WindowExists()) if (Config.Selector.WindowExists())
{ {
foreach (var action in OverlayHiddenActions) foreach (var action in OverlayHiddenActions)
{ {
@ -418,7 +414,7 @@ namespace VDash.Overlay
#region Acutally Render #region Acutally Render
//Redundant check, but w/e //Redundant check, but w/e
if (Selector.WindowExists() && windowHandle != IntPtr.Zero) if (Config.Selector.WindowExists() && windowHandle != IntPtr.Zero)
{ {
var rect = new User32.Rect(); var rect = new User32.Rect();
User32.GetClientRect(windowHandle, ref rect); User32.GetClientRect(windowHandle, ref rect);
@ -621,7 +617,7 @@ namespace VDash.Overlay
public void SetOverlayName(string newName) public void SetOverlayName(string newName)
{ {
OpenVR.Overlay.SetOverlayName(m_OverlayHandle, newName); OpenVR.Overlay.SetOverlayName(m_OverlayHandle, newName);
m_Name = newName; //Config.Name = newName;
} }
public float GetOverlayWidth() public float GetOverlayWidth()
@ -635,5 +631,10 @@ namespace VDash.Overlay
{ {
OpenVR.Overlay.SetOverlayWidthInMeters(m_OverlayHandle, width); OpenVR.Overlay.SetOverlayWidthInMeters(m_OverlayHandle, width);
} }
public override string ToString()
{
return Config.Name;
}
} }
} }

17
VDash/OverlayManager.cs Normal file
View File

@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VDash.Overlay;
namespace VDash
{
public class OverlayManager
{
public ObservableCollection<IOverlay> Overlays { get; internal set; } = new ObservableCollection<IOverlay>();
}
}

View File

@ -0,0 +1,30 @@
<UserControl x:Class="VDash.UI.CreateNewOverlay"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:VDash.UI"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="34" />
<RowDefinition Height="*" />
<RowDefinition Height="25" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" Margin="5,5,5,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="104"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="0,0,5,0" VerticalAlignment="Center">New Overlay Type:</TextBlock>
<ComboBox x:Name="cbOverlayType" Grid.Column="1" ItemsSource="{Binding EligibleOverlays}"
SelectionChanged="cbOverlayType_SelectionChanged"></ComboBox>
</Grid>
<Border x:Name="bdrContent" Grid.Row="1" Background="White" BorderBrush="Gainsboro" Margin="5" BorderThickness="1" Padding="5"/>
<Button x:Name="btnCreate" Grid.Row="2" Click="btnCreate_Click">Create</Button>
</Grid>
</UserControl>

View File

@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VDash.Overlay;
namespace VDash.UI
{
/// <summary>
/// Interaction logic for CreateNewOverlay.xaml
/// </summary>
public partial class CreateNewOverlay : UserControl
{
public event EventHandler Created;
public OverlayTypeWrapper[] EligibleOverlays { get; private set; } = {
new OverlayTypeWrapper("Window Overlay", typeof(WindowOverlay), new WindowOverlayEditor()),
new OverlayTypeWrapper("Monitor Overlay", typeof(MonitorOverlay), new MonitorOverlayEditor())
};
public CreateNewOverlay()
{
InitializeComponent();
DataContext = this;
}
private void cbOverlayType_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
bdrContent.Child = ((OverlayTypeWrapper)cbOverlayType.SelectedItem).Control;
}
private void btnCreate_Click(object sender, RoutedEventArgs e)
{
var wrapper = ((OverlayTypeWrapper)cbOverlayType.SelectedItem);
var config = wrapper.Editor.Config;
if (String.IsNullOrWhiteSpace(config.Key))
{
config.Key = RandomString(8, true);
}
IOverlay overlay = (IOverlay)Activator.CreateInstance(wrapper.OverlayType, new object[] { config });
overlay.Create();
MainWindow.OverlayManager.Overlays.Add(overlay);
Created?.Invoke(this, null);
}
// Generate a random string with a given size
public string RandomString(int size, bool lowerCase)
{
StringBuilder builder = new StringBuilder();
Random random = new Random();
char ch;
for (int i = 0; i < size; i++)
{
ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26 * random.NextDouble() + 65)));
builder.Append(ch);
}
if (lowerCase)
return builder.ToString().ToLower();
return builder.ToString();
}
}
public class OverlayTypeWrapper
{
public Type OverlayType { get; private set; }
public string FriendlyName { 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 override string ToString()
{
return FriendlyName;
}
}
}

View File

@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VDash.Overlay.Config;
namespace VDash.UI
{
public interface IOverlayEditor
{
IOverlayConfig Config { get; }
}
}

View File

@ -0,0 +1,30 @@
<UserControl x:Class="VDash.UI.MonitorOverlayEditor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:VDash.UI"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="25" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,5,0">Name:</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,5,0">Monitor:</TextBlock>
<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"></ComboBox>
</Grid>
</UserControl>

View File

@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VDash.Overlay.Config;
using static VDash.Utilities.User32;
namespace VDash.UI
{
/// <summary>
/// Interaction logic for MonitorOverlayEditor.xaml
/// </summary>
public partial class MonitorOverlayEditor : UserControl,IOverlayEditor
{
public IOverlayConfig Config { get { return OverlayConfig; } }
public MonitorOverlayConfig OverlayConfig { get; set; } = new MonitorOverlayConfig();
public MonitorOverlayEditor(ref MonitorOverlayConfig config)
{
InitializeComponent();
OverlayConfig = config;
DataContext = OverlayConfig;
cbMontitor.ItemsSource = GetDisplays();
}
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

@ -0,0 +1,22 @@
<UserControl x:Class="VDash.UI.ProcessSelectorEditor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:VDash.UI"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="25" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center">Process Name:</TextBlock>
<TextBox x:Name="tbProcessName" Grid.Row="0" Grid.Column="1" Text="{Binding ProcessName}" Margin="5,0,0,0"/>
</Grid>
</UserControl>

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VDash.WindowSelectors;
namespace VDash.UI
{
/// <summary>
/// Interaction logic for ProcessSelectorEditor.xaml
/// </summary>
public partial class ProcessSelectorEditor : UserControl
{
public FromProcessName Selector { get; private set; }
public ProcessSelectorEditor(ref FromProcessName selector)
{
InitializeComponent();
Selector = selector;
DataContext = Selector;
}
}
}

View File

@ -0,0 +1,46 @@
<UserControl x:Class="VDash.UI.WindowOverlayEditor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:VDash.UI"
mc:Ignorable="d"
d:DesignHeight="350" d:DesignWidth="600">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="Auto" />
<RowDefinition Height="40" />
<RowDefinition Height="40" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,5,0">Name:</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,5,0">Window Selector:</TextBlock>
<TextBlock Grid.Row="3" Grid.Column="0" HorizontalAlignment="Right"
VerticalAlignment="Center" Margin="0,0,5,0" TextWrapping="WrapWithOverflow">Auto dashboard name:</TextBlock>
<TextBlock Grid.Row="4" Grid.Column="0" HorizontalAlignment="Right"
VerticalAlignment="Center" Margin="0,0,5,0" TextWrapping="WrapWithOverflow">Hide when no window found:</TextBlock>
<TextBox x:Name="tbName" Grid.Row="0" Grid.Column="1" Margin="0,0,0,3" Text="{Binding Name}"/>
<ComboBox x:Name="cbSelector" Grid.Row="1" Grid.Column="1" Margin="0,3,0,3"
SelectionChanged="cbSelector_SelectionChanged"/>
<Border x:Name="bdrSelector" Grid.Row="2" Grid.Column="1" Margin="3,3,3,3" Padding="3,3,3,3"
Background="White" BorderBrush="Gainsboro" BorderThickness="1"/>
<CheckBox x:Name="chkAutoName" Grid.Row="3" Grid.Column="1"
HorizontalAlignment="Left" VerticalAlignment="Center" IsChecked="{Binding UpdateDashboardName}"/>
<CheckBox x:Name="chkDestroyNoWindow" Grid.Row="4" Grid.Column="1"
HorizontalAlignment="Left" VerticalAlignment="Center" IsChecked="{Binding DestroyOnNoWindowFound}"/>
</Grid>
</UserControl>

View File

@ -0,0 +1,96 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VDash.Overlay.Config;
using VDash.WindowSelectors;
namespace VDash.UI
{
/// <summary>
/// Interaction logic for CreateWindowOverlay.xaml
/// </summary>
public partial class WindowOverlayEditor : UserControl,IOverlayEditor
{
public WindowOverlayConfig OverlayConfig { get; set; } = new WindowOverlayConfig();
public SelectorWrapper[] Selectors { get; private set; } =
{
new SelectorWrapper("By Process Name", typeof(FromProcessName), typeof(ProcessSelectorEditor)),
new SelectorWrapper("By Window Title", typeof(FromWindowTitle), typeof(WindowSelectorEditor))
};
public IOverlayConfig Config { get { return OverlayConfig; } }
public WindowOverlayEditor()
{
InitializeComponent();
DataContext = OverlayConfig;
if (OverlayConfig.Selector != null)
{
SelectorWrapper wrapper = Selectors.Single(x => x.SelectorType == OverlayConfig.Selector.GetType());
IWindowSelector selector = OverlayConfig.Selector;
UserControl editor = (UserControl)Activator.CreateInstance(wrapper.EditorType, OverlayConfig);
wrapper.Editor = editor;
}
cbSelector.ItemsSource = Selectors;
}
public WindowOverlayEditor(ref WindowOverlayConfig config)
{
InitializeComponent();
OverlayConfig = config;
DataContext = OverlayConfig;
cbSelector.ItemsSource = Selectors;
}
public class SelectorWrapper
{
public string FriendlyName { get; set; }
//public IWindowSelector Selector{ get; private set; }
public Type SelectorType { get; set; }
//public UserControl Control { get; set; }
public Type EditorType { get; set; }
public IWindowSelector Selector { get; set; }
public UserControl Editor { get; set; } = null;
public SelectorWrapper(string friendlyName, Type selectorType, Type editorType)
{
FriendlyName = friendlyName;
SelectorType = selectorType;
EditorType = editorType;
Selector = (IWindowSelector)Activator.CreateInstance(selectorType);
Editor = (UserControl)Activator.CreateInstance(EditorType, new object[] { Selector });
}
public override string ToString()
{
return FriendlyName;
}
}
private void cbSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var wrapper = (SelectorWrapper)cbSelector.SelectedItem;
OverlayConfig.Selector = wrapper.Selector;
bdrSelector.Child = wrapper.Editor;
}
}
}

View File

@ -0,0 +1,26 @@
<UserControl x:Class="VDash.UI.WindowSelectorEditor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:VDash.UI"
mc:Ignorable="d"
d:DesignHeight="100" d:DesignWidth="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,4,0">Search Type:</TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,4,0">Search Text:</TextBlock>
<ComboBox x:Name="cbSearchType" Grid.Row="0" Grid.Column="1" Margin="3" SelectionChanged="cbSearchType_SelectionChanged"/>
<TextBox x:Name="tbSearch" Grid.Row="1" Grid.Column="1" Margin="3" Text="{Binding TitleFilter}"/>
</Grid>
</UserControl>

View File

@ -0,0 +1,39 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using VDash.WindowSelectors;
namespace VDash.UI
{
/// <summary>
/// Interaction logic for WindowSelectorEditor.xaml
/// </summary>
public partial class WindowSelectorEditor : UserControl
{
public FromWindowTitle Selector { get; set; }
public WindowSelectorEditor(ref FromWindowTitle selector)
{
InitializeComponent();
Selector = selector;
cbSearchType.ItemsSource = Enum.GetValues(typeof(FromWindowTitle.TitleSearchType));
DataContext = selector;
}
private void cbSearchType_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Selector.SearchType = (FromWindowTitle.TitleSearchType)cbSearchType.SelectedItem;
}
}
}

View File

@ -642,6 +642,11 @@ namespace VDash.Utilities
public Rect MonitorArea { get; set; } public Rect MonitorArea { get; set; }
public Rect WorkArea { get; set; } public Rect WorkArea { get; set; }
public MonitorInfoEx MonitorInfo { get; set; } public MonitorInfoEx MonitorInfo { get; set; }
public override string ToString()
{
return MonitorInfo.DeviceName + (Primary ? "(Primary)" : "");
}
} }
// size of a device name string // size of a device name string
private const int CCHDEVICENAME = 32; private const int CCHDEVICENAME = 32;
@ -699,20 +704,13 @@ namespace VDash.Utilities
} }
} }
/// <summary>
/// Collection of display information
/// </summary>
public class DisplayInfoCollection : List<DisplayInfo>
{
}
/// <summary> /// <summary>
/// Returns the number of Displays using the Win32 functions /// Returns the number of Displays using the Win32 functions
/// </summary> /// </summary>
/// <returns>Collection of Display Info</returns> /// <returns>Collection of Display Info</returns>
public static DisplayInfoCollection GetDisplays() public static DisplayInfo[] GetDisplays()
{ {
DisplayInfoCollection col = new DisplayInfoCollection(); List<DisplayInfo> col = new List<DisplayInfo>();
EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero,
delegate (IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData) delegate (IntPtr hMonitor, IntPtr hdcMonitor, ref Rect lprcMonitor, IntPtr dwData)
@ -733,7 +731,7 @@ namespace VDash.Utilities
} }
return true; return true;
}, IntPtr.Zero); }, IntPtr.Zero);
return col; return col.ToArray();
} }
#endregion #endregion

View File

@ -85,16 +85,36 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
</ApplicationDefinition> </ApplicationDefinition>
<Compile Include="OverlayManager.cs" />
<Compile Include="Overlay\Actions\BringWindowToFrontAction.cs" /> <Compile Include="Overlay\Actions\BringWindowToFrontAction.cs" />
<Compile Include="Overlay\Actions\IOverlayAction.cs" /> <Compile Include="Overlay\Actions\IOverlayAction.cs" />
<Compile Include="Overlay\Actions\MaximizeWindowAction.cs" /> <Compile Include="Overlay\Actions\MaximizeWindowAction.cs" />
<Compile Include="Overlay\Actions\ResizeWindowAction.cs" /> <Compile Include="Overlay\Actions\ResizeWindowAction.cs" />
<Compile Include="Overlay\Actions\RestoreWindowAction.cs" /> <Compile Include="Overlay\Actions\RestoreWindowAction.cs" />
<Compile Include="Overlay\Config\IOverlayConfig.cs" />
<Compile Include="Overlay\Config\MonitorOverlayConfig.cs" />
<Compile Include="Overlay\IOverlay.cs" /> <Compile Include="Overlay\IOverlay.cs" />
<Compile Include="Overlay\MonitorOverlay.cs" /> <Compile Include="Overlay\MonitorOverlay.cs" />
<Compile Include="Overlay\Config\WindowOverlayConfig.cs" />
<Compile Include="UI\CreateNewOverlay.xaml.cs">
<DependentUpon>CreateNewOverlay.xaml</DependentUpon>
</Compile>
<Compile Include="UI\IOverlayEditor.cs" />
<Compile Include="UI\MonitorOverlayEditor.xaml.cs">
<DependentUpon>MonitorOverlayEditor.xaml</DependentUpon>
</Compile>
<Compile Include="UI\ProcessSelectorEditor.xaml.cs">
<DependentUpon>ProcessSelectorEditor.xaml</DependentUpon>
</Compile>
<Compile Include="UI\WindowOverlayEditor.xaml.cs">
<DependentUpon>WindowOverlayEditor.xaml</DependentUpon>
</Compile>
<Compile Include="UI\WindowSelectorEditor.xaml.cs">
<DependentUpon>WindowSelectorEditor.xaml</DependentUpon>
</Compile>
<Compile Include="Utilities\User32.cs" /> <Compile Include="Utilities\User32.cs" />
<Compile Include="WindowSelectors\FromProcessName.cs" /> <Compile Include="WindowSelectors\FromProcessName.cs" />
<Compile Include="WindowSelectors\FromWindowName.cs" /> <Compile Include="WindowSelectors\FromWindowTitle.cs" />
<Compile Include="WindowSelectors\IWindowSelector.cs" /> <Compile Include="WindowSelectors\IWindowSelector.cs" />
<Page Include="MainWindow.xaml"> <Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
@ -109,6 +129,26 @@
<DependentUpon>MainWindow.xaml</DependentUpon> <DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Page Include="UI\CreateNewOverlay.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="UI\MonitorOverlayEditor.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="UI\ProcessSelectorEditor.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="UI\WindowOverlayEditor.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="UI\WindowSelectorEditor.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="OpenVR\openvr_api.cs" /> <Compile Include="OpenVR\openvr_api.cs" />

View File

@ -7,7 +7,7 @@ namespace VDash.WindowSelectors
{ {
public class FromProcessName : IWindowSelector public class FromProcessName : IWindowSelector
{ {
string m_ProcName = ""; public string ProcessName { get; set; } = "";
public FromProcessName(string procName) public FromProcessName(string procName)
{ {
if (string.IsNullOrWhiteSpace(procName)) if (string.IsNullOrWhiteSpace(procName))
@ -15,7 +15,12 @@ namespace VDash.WindowSelectors
throw new ArgumentNullException("procName", "procName must not be null, whitespace, or empty."); throw new ArgumentNullException("procName", "procName must not be null, whitespace, or empty.");
} }
m_ProcName = procName; ProcessName = procName;
}
public FromProcessName()
{
} }
Process[] processes = null; Process[] processes = null;
@ -23,7 +28,7 @@ namespace VDash.WindowSelectors
{ {
if(processes == null) if(processes == null)
{ {
processes = Process.GetProcessesByName(m_ProcName); processes = Process.GetProcessesByName(ProcessName);
} }
return processes; return processes;
@ -35,7 +40,7 @@ namespace VDash.WindowSelectors
if (procs.Count() <= 0) if (procs.Count() <= 0)
{ {
throw new WindowNotFoundException($"No process found with name {m_ProcName}."); throw new WindowNotFoundException($"No process found with name {ProcessName}.");
} }
return procs.First(); return procs.First();
} }
@ -49,7 +54,7 @@ namespace VDash.WindowSelectors
var ret = WindowInfo.GetWindowList().SingleOrDefault(x => x.hWnd == GetWindowHandle()); var ret = WindowInfo.GetWindowList().SingleOrDefault(x => x.hWnd == GetWindowHandle());
if(ret == null) if(ret == null)
{ {
throw new WindowNotFoundException($"Unable to locate window for process {m_ProcName}."); throw new WindowNotFoundException($"Unable to locate window for process {ProcessName}.");
} }
return ret; return ret;
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using VDash.Utilities;
namespace VDash.WindowSelectors namespace VDash.WindowSelectors
{ {
@ -42,6 +43,10 @@ namespace VDash.WindowSelectors
SearchType = searchType; SearchType = searchType;
} }
public FromWindowTitle()
{
}
internal WindowInfo GetWindowUsingFilter() internal WindowInfo GetWindowUsingFilter()
{ {
var windows = WindowInfo.GetWindowList(); var windows = WindowInfo.GetWindowList();
@ -82,15 +87,17 @@ namespace VDash.WindowSelectors
public bool WindowExists() public bool WindowExists()
{ {
try //try
{ //{
var window = Window; // var window = Window;
} //}
catch (WindowNotFoundException) //catch (WindowNotFoundException)
{ //{
return false; // return false;
} //}
return true; //return true;
return User32.IsWindow(GetWindowHandle());
} }
public enum TitleSearchType public enum TitleSearchType