Skip to content

Commit

Permalink
Merge pull request #5 from aeoth/master
Browse files Browse the repository at this point in the history
Basic settings UI + screen iteration
  • Loading branch information
andrewtobin committed Feb 14, 2012
2 parents 9364b27 + 084271f commit d9f51ac
Show file tree
Hide file tree
Showing 9 changed files with 314 additions and 20 deletions.
5 changes: 5 additions & 0 deletions src/Carnac.Logic/Carnac.Logic.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="DetailedScreen.cs" />
<Compile Include="DEVMODE.cs" />
<Compile Include="DisplayDeviceStateFlags.cs" />
<Compile Include="DISPLAY_DEVICE.cs" />
<Compile Include="POINTL.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
Expand Down
110 changes: 110 additions & 0 deletions src/Carnac.Logic/DEVMODE.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using System;
using System.Runtime.InteropServices;

namespace Carnac.ViewModels
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DEVMODE
{
// You can define the following constant
// but OUTSIDE the structure because you know
// that size and layout of the structure
// is very important
// CCHDEVICENAME = 32 = 0x50
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmDeviceName;
// In addition you can define the last character array
// as following:
//[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
//public Char[] dmDeviceName;

// After the 32-bytes array
[MarshalAs(UnmanagedType.U2)]
public UInt16 dmSpecVersion;

[MarshalAs(UnmanagedType.U2)]
public UInt16 dmDriverVersion;

[MarshalAs(UnmanagedType.U2)]
public UInt16 dmSize;

[MarshalAs(UnmanagedType.U2)]
public UInt16 dmDriverExtra;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmFields;

public POINTL dmPosition;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmDisplayOrientation;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmDisplayFixedOutput;

[MarshalAs(UnmanagedType.I2)]
public Int16 dmColor;

[MarshalAs(UnmanagedType.I2)]
public Int16 dmDuplex;

[MarshalAs(UnmanagedType.I2)]
public Int16 dmYResolution;

[MarshalAs(UnmanagedType.I2)]
public Int16 dmTTOption;

[MarshalAs(UnmanagedType.I2)]
public Int16 dmCollate;

// CCHDEVICENAME = 32 = 0x50
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string dmFormName;
// Also can be defined as
//[MarshalAs(UnmanagedType.ByValArray,
// SizeConst = 32, ArraySubType = UnmanagedType.U1)]
//public Byte[] dmFormName;

[MarshalAs(UnmanagedType.U2)]
public UInt16 dmLogPixels;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmBitsPerPel;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmPelsWidth;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmPelsHeight;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmDisplayFlags;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmDisplayFrequency;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmICMMethod;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmICMIntent;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmMediaType;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmDitherType;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmReserved1;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmReserved2;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmPanningWidth;

[MarshalAs(UnmanagedType.U4)]
public UInt32 dmPanningHeight;
}
}
21 changes: 21 additions & 0 deletions src/Carnac.Logic/DISPLAY_DEVICE.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Runtime.InteropServices;

namespace Carnac.ViewModels
{
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DISPLAY_DEVICE
{
[MarshalAs(UnmanagedType.U4)]
public int cb;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string DeviceName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceString;
[MarshalAs(UnmanagedType.U4)]
public DisplayDeviceStateFlags StateFlags;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceID;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
public string DeviceKey;
}
}
15 changes: 15 additions & 0 deletions src/Carnac.Logic/DetailedScreen.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace Carnac.ViewModels
{
public class DetailedScreen
{
public int Index { get; set; }
public string FriendlyName { get; set; }
public double Width { get; set; }
public double Height { get; set; }

public double RelativeHeight { get; set; }
public double RelativeWidth { get; set; }

public double Top { get; set; }
}
}
24 changes: 24 additions & 0 deletions src/Carnac.Logic/DisplayDeviceStateFlags.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;

namespace Carnac.ViewModels
{
[Flags()]
public enum DisplayDeviceStateFlags : int
{
/// <summary>The device is part of the desktop.</summary>
AttachedToDesktop = 0x1,
MultiDriver = 0x2,
/// <summary>The device is part of the desktop.</summary>
PrimaryDevice = 0x4,
/// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary>
MirroringDriver = 0x8,
/// <summary>The device is VGA compatible.</summary>
VGACompatible = 0x16,
/// <summary>The device is removable; it cannot be the primary display.</summary>
Removable = 0x20,
/// <summary>The device has more display modes than its output devices support.</summary>
ModesPruned = 0x8000000,
Remote = 0x4000000,
Disconnect = 0x2000000
}
}
11 changes: 11 additions & 0 deletions src/Carnac.Logic/POINTL.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System.Runtime.InteropServices;

namespace Carnac.ViewModels
{
[StructLayout(LayoutKind.Sequential)]
public struct POINTL
{
public int x;
public int y;
}
}
6 changes: 6 additions & 0 deletions src/Carnac/Carnac.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@
<ItemGroup>
<Resource Include="Analects\Loader\Instructions.txt" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Carnac.Logic\Carnac.Logic.csproj">
<Project>{614470A0-432C-46EB-B0EB-DE0A9062FC22}</Project>
<Name>Carnac.Logic</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
<Import Project="Analects\Loader\EmbedAssemblies.targets" />
Expand Down
66 changes: 66 additions & 0 deletions src/Carnac/ViewModels/ShellViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.InteropServices;
using Caliburn.Micro;
using Carnac.KeyMonitor;
using System.ComponentModel.Composition;
Expand All @@ -9,11 +11,75 @@ namespace Carnac.ViewModels
[Export(typeof(IShell))]
public class ShellViewModel :Screen, IShell, IObserver<InterceptKeyEventArgs>
{
[DllImport("user32.dll")]
static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);

[DllImport("User32.dll")]
static extern bool EnumDisplaySettings(string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode);

private ObservableCollection<DetailedScreen> _screens;

public ObservableCollection<DetailedScreen> Screens
{
get
{
return _screens;
}
set { _screens = value; }
}
private IDisposable keySubscription;

public ShellViewModel()
{
Keys = new ObservableCollection<string>();
Screens = new ObservableCollection<DetailedScreen>();

int index = 1;
var d = new DISPLAY_DEVICE();
d.cb = Marshal.SizeOf(d);
try
{
for (uint id = 0; EnumDisplayDevices(null, id, ref d, 0); id++)
{
d.cb = Marshal.SizeOf(d);

var x = new DISPLAY_DEVICE();
x.cb = Marshal.SizeOf(x);

//Get the actual monitor
EnumDisplayDevices(d.DeviceName, 0, ref x, 0);

if (string.IsNullOrEmpty(x.DeviceName) || string.IsNullOrEmpty(x.DeviceString))
continue;


var screen = new DetailedScreen { FriendlyName = x.DeviceString, Index = index++ };

var mode = new DEVMODE();
mode.dmSize = (ushort)Marshal.SizeOf(mode);
if (EnumDisplaySettings(d.DeviceName, -1, ref mode))
{
screen.Width = (int)mode.dmPelsWidth;
screen.Height = (int)mode.dmPelsHeight;
screen.Top = (int)mode.dmPosition.y;

}

Screens.Add(screen);
}
}
catch (Exception ex)
{
//log this
}

var maxWidth = Screens.OrderByDescending(s => s.Width).FirstOrDefault().Width;
foreach (var s in Screens)
{
s.RelativeWidth = 200 * (s.Width / maxWidth);
s.RelativeHeight = s.RelativeWidth * (s.Height / s.Width);
s.Top *= (s.RelativeHeight / s.Height);
}
}

public ObservableCollection<string> Keys { get; private set; }
Expand Down
76 changes: 56 additions & 20 deletions src/Carnac/Views/ShellView.xaml
Original file line number Diff line number Diff line change
@@ -1,37 +1,73 @@
<Window x:Class="Carnac.Views.ShellView"
<Controls:MetroWindow x:Class="Carnac.Views.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:Behaviours="clr-namespace:MahApps.Metro.Behaviours;assembly=MahApps.Metro"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
d:DataContext="{d:DesignInstance ViewModels:ShellViewModel}" xmlns:ViewModels="clr-namespace:Carnac.ViewModels" MouseDown="OnMouseDown"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" MouseDown="OnMouseDown"
ShowInTaskbar="False"
Topmost="True"
ShowTitleBar="False"
mc:Ignorable="d"
Width="200"
Height="150">
Width="606"
Height="369">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colours.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.AnimatedSingleRowTabControl.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<i:Interaction.Behaviors>
<Behaviours:BorderlessWindowBehavior />
</i:Interaction.Behaviors>
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Controls:WindowCommands HorizontalAlignment="Right" />
<ItemsControl ItemsSource="{Binding Keys}" />
</Grid>
</Window>

<Window.Foreground>
<SolidColorBrush Color="{DynamicResource BlackBrush}" />
</Window.Foreground>
<TabControl Margin="0,12">
<TabItem Header="General">
<ListBox ItemsSource="{Binding Screens}" BorderBrush="{x:Null}" Background="{x:Null}" VerticalAlignment="Top">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="VerticalAlignment" Value="Bottom" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="5,5,5,5">
<Grid HorizontalAlignment="Left" Height="{Binding RelativeHeight}" Margin="0" Width="{Binding RelativeWidth}">
<Rectangle Fill="{DynamicResource AccentColorBrush}"/>
<TextBlock FontWeight="SemiBold" TextWrapping="Wrap" Foreground="White" FontSize="96" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{Binding Index}" />
<RadioButton x:Name="rbTL" Content="" HorizontalAlignment="Left" VerticalAlignment="Top" />
<RadioButton x:Name="rbBL" Content="" HorizontalAlignment="Left" VerticalAlignment="Bottom" />
<RadioButton x:Name="rbTR" Content="" HorizontalAlignment="Right" VerticalAlignment="Top" />
<RadioButton x:Name="rbBR" Content="" HorizontalAlignment="Right" VerticalAlignment="Bottom" />
</Grid>
<TextBlock FontWeight="SemiBold" HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding FriendlyName}" FontSize="18.667"/>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" FontSize="14">
<Run Text="{Binding Width}"/> x <Run Text="{Binding Height}"/>
</TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</TabItem>
<TabItem Header="Keys">
<ItemsControl Margin="12" ItemsSource="{Binding Keys}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ItemsControl.Foreground>
<SolidColorBrush Color="White" />
</ItemsControl.Foreground>
</ItemsControl>
</TabItem>
<TabItem Header="Recording"/>
<TabItem Header="Appearance"/>
<TabItem Header="About"/>
</TabControl>
</Controls:MetroWindow>

0 comments on commit d9f51ac

Please sign in to comment.