mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-01-18 06:29:44 +08:00
Merge pull request #391 from microsoft/user/bretan/fz-multimon
Fix for #195 - Fancy Zones new editor needs to support multiple monitors Fix for #292 - Zone Editor opens behind PowerToys Window
This commit is contained in:
commit
a54e4299aa
@ -27,27 +27,26 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReser
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: multimon support, need to pass the HMONITOR from the editor to here instead
|
|
||||||
// of using MonitorFromPoint
|
|
||||||
// This function is exported and called from FancyZonesEditor.exe to save a layout from the editor.
|
// This function is exported and called from FancyZonesEditor.exe to save a layout from the editor.
|
||||||
STDAPI PersistZoneSet(
|
STDAPI PersistZoneSet(
|
||||||
PCWSTR activeKey, // Registry key holding ActiveZoneSet
|
PCWSTR activeKey, // Registry key holding ActiveZoneSet
|
||||||
PCWSTR resolutionKey, // Registry key for screen resolution
|
PCWSTR resolutionKey, // Registry key to persist ZoneSet to
|
||||||
|
HMONITOR monitor,
|
||||||
WORD layoutId, // LayoutModel Id
|
WORD layoutId, // LayoutModel Id
|
||||||
int zoneCount, // Number of zones in zones
|
int zoneCount, // Number of zones in zones
|
||||||
int zones[]) // Array of zones serialized in left/top/right/bottom chunks
|
int zones[]) // Array of zones serialized in left/top/right/bottom chunks
|
||||||
{
|
{
|
||||||
// See if we have already persisted this layout we can update.
|
// See if we have already persisted this layout we can update.
|
||||||
UUID id{GUID_NULL};
|
UUID id{GUID_NULL};
|
||||||
if (wil::unique_hkey key{ RegistryHelpers::OpenKey(resolutionKey) })
|
if (wil::unique_hkey key{ RegistryHelpers::OpenKey(resolutionKey) })
|
||||||
{
|
{
|
||||||
ZoneSetPersistedData data{};
|
ZoneSetPersistedData data{};
|
||||||
DWORD dataSize = sizeof(data);
|
DWORD dataSize = sizeof(data);
|
||||||
wchar_t value[256]{};
|
wchar_t value[256]{};
|
||||||
DWORD valueLength = ARRAYSIZE(value);
|
DWORD valueLength = ARRAYSIZE(value);
|
||||||
DWORD i = 0;
|
DWORD i = 0;
|
||||||
while (RegEnumValueW(key.get(), i++, value, &valueLength, nullptr, nullptr, reinterpret_cast<BYTE*>(&data), &dataSize) == ERROR_SUCCESS)
|
while (RegEnumValueW(key.get(), i++, value, &valueLength, nullptr, nullptr, reinterpret_cast<BYTE*>(&data), &dataSize) == ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
if (data.LayoutId == layoutId)
|
if (data.LayoutId == layoutId)
|
||||||
{
|
{
|
||||||
if (data.ZoneCount == zoneCount)
|
if (data.ZoneCount == zoneCount)
|
||||||
@ -73,7 +72,7 @@ STDAPI PersistZoneSet(
|
|||||||
ZoneSetConfig(
|
ZoneSetConfig(
|
||||||
id,
|
id,
|
||||||
layoutId,
|
layoutId,
|
||||||
MonitorFromPoint({}, MONITOR_DEFAULTTOPRIMARY),
|
reinterpret_cast<HMONITOR>(monitor),
|
||||||
resolutionKey,
|
resolutionKey,
|
||||||
ZoneSetLayout::Custom,
|
ZoneSetLayout::Custom,
|
||||||
0, 0, 0));
|
0, 0, 0));
|
||||||
|
@ -20,7 +20,6 @@ namespace FancyZonesEditor
|
|||||||
private ushort _idInitial = 0;
|
private ushort _idInitial = 0;
|
||||||
public App()
|
public App()
|
||||||
{
|
{
|
||||||
//init settings
|
|
||||||
_settings = new Settings();
|
_settings = new Settings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,8 +63,7 @@ namespace FancyZonesEditor
|
|||||||
}
|
}
|
||||||
|
|
||||||
foundModel.IsSelected = true;
|
foundModel.IsSelected = true;
|
||||||
// TODO: multimon
|
|
||||||
// Pass in the correct args to show on the desired monitor
|
|
||||||
EditorOverlay overlay = new EditorOverlay();
|
EditorOverlay overlay = new EditorOverlay();
|
||||||
overlay.Show();
|
overlay.Show();
|
||||||
overlay.DataContext = foundModel;
|
overlay.DataContext = foundModel;
|
||||||
|
@ -41,7 +41,7 @@ namespace FancyZonesEditor
|
|||||||
}
|
}
|
||||||
else if (xDelta > 0)
|
else if (xDelta > 0)
|
||||||
{
|
{
|
||||||
xDelta = Math.Min(xDelta, c_workArea.Width - rect.Width - rect.X);
|
xDelta = Math.Min(xDelta, _settings.WorkArea.Width - rect.Width - rect.X);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (yDelta < 0)
|
if (yDelta < 0)
|
||||||
@ -50,7 +50,7 @@ namespace FancyZonesEditor
|
|||||||
}
|
}
|
||||||
else if (yDelta > 0)
|
else if (yDelta > 0)
|
||||||
{
|
{
|
||||||
yDelta = Math.Min(yDelta, c_workArea.Height - rect.Height - rect.Y);
|
yDelta = Math.Min(yDelta, _settings.WorkArea.Height - rect.Height - rect.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
rect.X += (int) xDelta;
|
rect.X += (int) xDelta;
|
||||||
@ -69,13 +69,13 @@ namespace FancyZonesEditor
|
|||||||
{
|
{
|
||||||
int newWidth = rect.Width + (int) xDelta;
|
int newWidth = rect.Width + (int) xDelta;
|
||||||
|
|
||||||
if (newWidth < 48)
|
if (newWidth < c_minZoneSize)
|
||||||
{
|
{
|
||||||
newWidth = 48;
|
newWidth = c_minZoneSize;
|
||||||
}
|
}
|
||||||
else if (newWidth > (c_workArea.Width - rect.X))
|
else if (newWidth > (_settings.WorkArea.Width - rect.X))
|
||||||
{
|
{
|
||||||
newWidth = (int) c_workArea.Width - rect.X;
|
newWidth = (int) _settings.WorkArea.Width - rect.X;
|
||||||
}
|
}
|
||||||
MinWidth = rect.Width = newWidth;
|
MinWidth = rect.Width = newWidth;
|
||||||
}
|
}
|
||||||
@ -84,13 +84,13 @@ namespace FancyZonesEditor
|
|||||||
{
|
{
|
||||||
int newHeight = rect.Height + (int)yDelta;
|
int newHeight = rect.Height + (int)yDelta;
|
||||||
|
|
||||||
if (newHeight < 48)
|
if (newHeight < c_minZoneSize)
|
||||||
{
|
{
|
||||||
newHeight = 48;
|
newHeight = c_minZoneSize;
|
||||||
}
|
}
|
||||||
else if (newHeight > (c_workArea.Height - rect.Y))
|
else if (newHeight > (_settings.WorkArea.Height - rect.Y))
|
||||||
{
|
{
|
||||||
newHeight = (int)c_workArea.Height - rect.Y;
|
newHeight = (int)_settings.WorkArea.Height - rect.Y;
|
||||||
}
|
}
|
||||||
MinHeight = rect.Height = newHeight;
|
MinHeight = rect.Height = newHeight;
|
||||||
}
|
}
|
||||||
@ -98,10 +98,7 @@ namespace FancyZonesEditor
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static int c_zIndex = 0;
|
private static int c_zIndex = 0;
|
||||||
|
private static int c_minZoneSize = 48;
|
||||||
// TODO: multimon
|
|
||||||
// This needs to be the work area of the monitor we get launched on
|
|
||||||
private static Rect c_workArea = System.Windows.SystemParameters.WorkArea;
|
|
||||||
|
|
||||||
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
|
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
@ -163,5 +160,7 @@ namespace FancyZonesEditor
|
|||||||
((Panel)Parent).Children.Remove(this);
|
((Panel)Parent).Children.Remove(this);
|
||||||
Model.RemoveZoneAt(ZoneIndex);
|
Model.RemoveZoneAt(ZoneIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Settings _settings = ((App)Application.Current).ZoneSettings;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,138 +1,135 @@
|
|||||||
using FancyZonesEditor.Models;
|
using FancyZonesEditor.Models;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.NetworkInformation;
|
using System.Net.NetworkInformation;
|
||||||
using System.Security.RightsManagement;
|
using System.Security.RightsManagement;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Data;
|
using System.Windows.Data;
|
||||||
using System.Windows.Documents;
|
using System.Windows.Documents;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
namespace FancyZonesEditor
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Interaction logic for Window1.xaml
|
|
||||||
/// </summary>
|
|
||||||
public partial class EditorOverlay : Window
|
|
||||||
{
|
|
||||||
public Int32Rect[] GetZoneRects()
|
|
||||||
{
|
|
||||||
// TODO: the ideal here is that the ArrangeRects logic is entirely inside the model, so we don't have to walk the UIElement children to get the rect info
|
|
||||||
Panel previewPanel = null;
|
|
||||||
|
|
||||||
if (_editor != null)
|
|
||||||
{
|
|
||||||
GridEditor gridEditor = _editor as GridEditor;
|
|
||||||
if (gridEditor != null)
|
|
||||||
{
|
|
||||||
previewPanel = gridEditor.PreviewPanel;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//CanvasEditor
|
|
||||||
previewPanel = ((CanvasEditor)_editor).Preview;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
previewPanel = _layoutPreview.PreviewPanel;
|
|
||||||
}
|
|
||||||
|
|
||||||
var count = previewPanel.Children.Count;
|
|
||||||
Int32Rect[] zones = new Int32Rect[count];
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (FrameworkElement child in previewPanel.Children)
|
|
||||||
{
|
|
||||||
Point topLeft = child.TransformToAncestor(previewPanel).Transform(new Point());
|
|
||||||
|
|
||||||
var right = topLeft.X + child.ActualWidth;
|
|
||||||
var bottom = topLeft.Y + child.ActualHeight;
|
|
||||||
zones[i].X = (int)topLeft.X;
|
|
||||||
zones[i].Y = (int)topLeft.Y;
|
|
||||||
zones[i].Width = (int)child.ActualWidth;
|
|
||||||
zones[i].Height = (int)child.ActualHeight;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return zones;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static EditorOverlay Current;
|
|
||||||
public EditorOverlay()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
Current = this;
|
|
||||||
|
|
||||||
// TODO: multimon
|
namespace FancyZonesEditor
|
||||||
// Need to set Left and Top to the correct monitor based on the
|
{
|
||||||
// foreground window passed in the command line arguments
|
/// <summary>
|
||||||
Rect workArea = System.Windows.SystemParameters.WorkArea;
|
/// Interaction logic for Window1.xaml
|
||||||
Left = workArea.Left;
|
/// </summary>
|
||||||
Top = workArea.Top;
|
public partial class EditorOverlay : Window
|
||||||
Width = workArea.Width;
|
{
|
||||||
Height = workArea.Height;
|
public Int32Rect[] GetZoneRects()
|
||||||
|
{
|
||||||
|
// TODO: the ideal here is that the ArrangeRects logic is entirely inside the model, so we don't have to walk the UIElement children to get the rect info
|
||||||
|
Panel previewPanel = null;
|
||||||
|
|
||||||
|
if (_editor != null)
|
||||||
|
{
|
||||||
|
GridEditor gridEditor = _editor as GridEditor;
|
||||||
|
if (gridEditor != null)
|
||||||
|
{
|
||||||
|
previewPanel = gridEditor.PreviewPanel;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//CanvasEditor
|
||||||
|
previewPanel = ((CanvasEditor)_editor).Preview;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
previewPanel = _layoutPreview.PreviewPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
var count = previewPanel.Children.Count;
|
||||||
|
Int32Rect[] zones = new Int32Rect[count];
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
foreach (FrameworkElement child in previewPanel.Children)
|
||||||
|
{
|
||||||
|
Point topLeft = child.TransformToAncestor(previewPanel).Transform(new Point());
|
||||||
|
|
||||||
|
var right = topLeft.X + child.ActualWidth;
|
||||||
|
var bottom = topLeft.Y + child.ActualHeight;
|
||||||
|
zones[i].X = (int)topLeft.X;
|
||||||
|
zones[i].Y = (int)topLeft.Y;
|
||||||
|
zones[i].Width = (int)child.ActualWidth;
|
||||||
|
zones[i].Height = (int)child.ActualHeight;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return zones;
|
||||||
}
|
}
|
||||||
|
|
||||||
void onLoad(object sender, RoutedEventArgs e)
|
public static EditorOverlay Current;
|
||||||
{
|
public EditorOverlay()
|
||||||
ShowLayoutPicker();
|
{
|
||||||
}
|
InitializeComponent();
|
||||||
|
Current = this;
|
||||||
public void ShowLayoutPicker()
|
|
||||||
{
|
Left = _settings.WorkArea.Left;
|
||||||
DataContext = null;
|
Top = _settings.WorkArea.Top;
|
||||||
|
Width = _settings.WorkArea.Width;
|
||||||
_editor = null;
|
Height = _settings.WorkArea.Height;
|
||||||
_layoutPreview = new LayoutPreview();
|
}
|
||||||
_layoutPreview.IsActualSize = true;
|
|
||||||
_layoutPreview.Opacity = 0.5;
|
void onLoad(object sender, RoutedEventArgs e)
|
||||||
Content = _layoutPreview;
|
{
|
||||||
|
ShowLayoutPicker();
|
||||||
MainWindow window = new MainWindow();
|
}
|
||||||
window.Owner = this;
|
|
||||||
window.Show();
|
public void ShowLayoutPicker()
|
||||||
}
|
{
|
||||||
|
DataContext = null;
|
||||||
// These event handlers are used to track the current state of the Shift and Ctrl keys on the keyboard
|
|
||||||
// They reflect that current state into properties on the Settings object, which the Zone view will listen to in editing mode
|
_editor = null;
|
||||||
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
_layoutPreview = new LayoutPreview();
|
||||||
{
|
_layoutPreview.IsActualSize = true;
|
||||||
_settings.IsShiftKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Shift);
|
_layoutPreview.Opacity = 0.5;
|
||||||
_settings.IsCtrlKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Control);
|
Content = _layoutPreview;
|
||||||
base.OnPreviewKeyDown(e);
|
|
||||||
}
|
MainWindow window = new MainWindow();
|
||||||
|
window.Owner = this;
|
||||||
protected override void OnPreviewKeyUp(KeyEventArgs e)
|
window.ShowActivated = true;
|
||||||
{
|
window.Show();
|
||||||
_settings.IsShiftKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Shift);
|
}
|
||||||
_settings.IsCtrlKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Control);
|
|
||||||
base.OnPreviewKeyUp(e);
|
// These event handlers are used to track the current state of the Shift and Ctrl keys on the keyboard
|
||||||
}
|
// They reflect that current state into properties on the Settings object, which the Zone view will listen to in editing mode
|
||||||
|
protected override void OnPreviewKeyDown(KeyEventArgs e)
|
||||||
public void Edit()
|
{
|
||||||
{
|
_settings.IsShiftKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Shift);
|
||||||
_layoutPreview = null;
|
_settings.IsCtrlKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Control);
|
||||||
if (DataContext is GridLayoutModel)
|
base.OnPreviewKeyDown(e);
|
||||||
{
|
}
|
||||||
_editor = new GridEditor();
|
|
||||||
}
|
protected override void OnPreviewKeyUp(KeyEventArgs e)
|
||||||
else if (DataContext is CanvasLayoutModel)
|
{
|
||||||
{
|
_settings.IsShiftKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Shift);
|
||||||
_editor = new CanvasEditor();
|
_settings.IsCtrlKeyPressed = Keyboard.Modifiers.HasFlag(ModifierKeys.Control);
|
||||||
}
|
base.OnPreviewKeyUp(e);
|
||||||
Content = _editor;
|
}
|
||||||
}
|
|
||||||
|
public void Edit()
|
||||||
private Settings _settings = ((App)Application.Current).ZoneSettings;
|
{
|
||||||
private LayoutPreview _layoutPreview;
|
_layoutPreview = null;
|
||||||
private UserControl _editor;
|
if (DataContext is GridLayoutModel)
|
||||||
}
|
{
|
||||||
}
|
_editor = new GridEditor();
|
||||||
|
}
|
||||||
|
else if (DataContext is CanvasLayoutModel)
|
||||||
|
{
|
||||||
|
_editor = new CanvasEditor();
|
||||||
|
}
|
||||||
|
Content = _editor;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Settings _settings = ((App)Application.Current).ZoneSettings;
|
||||||
|
private LayoutPreview _layoutPreview;
|
||||||
|
private UserControl _editor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -155,7 +155,8 @@ namespace FancyZonesEditor.Models
|
|||||||
|
|
||||||
internal delegate int PersistZoneSet(
|
internal delegate int PersistZoneSet(
|
||||||
[MarshalAs(UnmanagedType.LPWStr)] string activeKey,
|
[MarshalAs(UnmanagedType.LPWStr)] string activeKey,
|
||||||
[MarshalAs(UnmanagedType.LPWStr)] string key,
|
[MarshalAs(UnmanagedType.LPWStr)] string resolutionKey,
|
||||||
|
uint monitor,
|
||||||
ushort layoutId,
|
ushort layoutId,
|
||||||
int zoneCount,
|
int zoneCount,
|
||||||
[MarshalAs(UnmanagedType.LPArray)] int[] zoneArray);
|
[MarshalAs(UnmanagedType.LPArray)] int[] zoneArray);
|
||||||
@ -186,14 +187,12 @@ namespace FancyZonesEditor.Models
|
|||||||
// Scale all the zones to the DPI and then pack them up to be marshalled.
|
// Scale all the zones to the DPI and then pack them up to be marshalled.
|
||||||
int zoneCount = zones.Length;
|
int zoneCount = zones.Length;
|
||||||
var zoneArray = new int[zoneCount * 4];
|
var zoneArray = new int[zoneCount * 4];
|
||||||
var graphics = System.Drawing.Graphics.FromHwnd(IntPtr.Zero);
|
|
||||||
float dpi = graphics.DpiX / 96;
|
|
||||||
for (int i = 0; i < zones.Length; i++)
|
for (int i = 0; i < zones.Length; i++)
|
||||||
{
|
{
|
||||||
var left = (int)(zones[i].X * dpi);
|
var left = (int)(zones[i].X * Settings.Dpi);
|
||||||
var top = (int)(zones[i].Y * dpi);
|
var top = (int)(zones[i].Y * Settings.Dpi);
|
||||||
var right = left + (int)(zones[i].Width * dpi);
|
var right = left + (int)(zones[i].Width * Settings.Dpi);
|
||||||
var bottom = top + (int)(zones[i].Height * dpi);
|
var bottom = top + (int)(zones[i].Height * Settings.Dpi);
|
||||||
|
|
||||||
var index = i * 4;
|
var index = i * 4;
|
||||||
zoneArray[index] = left;
|
zoneArray[index] = left;
|
||||||
@ -202,22 +201,8 @@ namespace FancyZonesEditor.Models
|
|||||||
zoneArray[index+3] = bottom;
|
zoneArray[index+3] = bottom;
|
||||||
}
|
}
|
||||||
|
|
||||||
string[] args = Environment.GetCommandLineArgs();
|
var persistZoneSet = Marshal.GetDelegateForFunctionPointer<Native.PersistZoneSet>(pfn);
|
||||||
if (args.Length > 1)
|
persistZoneSet(Settings.UniqueKey, Settings.WorkAreaKey, Settings.Monitor, _id, zoneCount, zoneArray);
|
||||||
{
|
|
||||||
// args[1] = registry key value of currently active ZoneSet
|
|
||||||
// args[2] = id of layout to load at startup
|
|
||||||
|
|
||||||
string uniqueId = args[1];
|
|
||||||
|
|
||||||
// TODO: multimon
|
|
||||||
double height = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;
|
|
||||||
double width = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;
|
|
||||||
var key = width.ToString() + "_" + height.ToString();
|
|
||||||
|
|
||||||
var persistZoneSet = Marshal.GetDelegateForFunctionPointer<Native.PersistZoneSet>(pfn);
|
|
||||||
persistZoneSet(uniqueId, key, _id, zoneCount, zoneArray);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly string c_registryPath = Settings.RegistryPath + "\\Layouts";
|
private static readonly string c_registryPath = Settings.RegistryPath + "\\Layouts";
|
||||||
|
@ -1,304 +1,375 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using FancyZonesEditor.Models;
|
using FancyZonesEditor.Models;
|
||||||
using System.Windows.Documents;
|
using System.Windows.Documents;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
|
||||||
namespace FancyZonesEditor
|
namespace FancyZonesEditor
|
||||||
{
|
{
|
||||||
//
|
//
|
||||||
// Settings
|
// Settings
|
||||||
// These are the configuration settings used by the rest of the editor
|
// These are the configuration settings used by the rest of the editor
|
||||||
// Other UIs in the editor will subscribe to change events on the properties to stay up to date as these properties change
|
// Other UIs in the editor will subscribe to change events on the properties to stay up to date as these properties change
|
||||||
//
|
//
|
||||||
public class Settings : INotifyPropertyChanged
|
public class Settings : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
public Settings()
|
public Settings()
|
||||||
{
|
{
|
||||||
Rect workArea = System.Windows.SystemParameters.WorkArea;
|
ParseCommandLineArgs();
|
||||||
|
|
||||||
// Initialize the five default layout models: Focus, Columns, Rows, Grid, and PriorityGrid
|
// Initialize the five default layout models: Focus, Columns, Rows, Grid, and PriorityGrid
|
||||||
_defaultModels = new List<LayoutModel>(5);
|
_defaultModels = new List<LayoutModel>(5);
|
||||||
_focusModel = new CanvasLayoutModel("Focus", c_focusModelId, (int)workArea.Width, (int)workArea.Height);
|
_focusModel = new CanvasLayoutModel("Focus", c_focusModelId, (int)_workArea.Width, (int)_workArea.Height);
|
||||||
_defaultModels.Add(_focusModel);
|
_defaultModels.Add(_focusModel);
|
||||||
|
|
||||||
_columnsModel = new GridLayoutModel("Columns", c_columnsModelId);
|
_columnsModel = new GridLayoutModel("Columns", c_columnsModelId);
|
||||||
_columnsModel.Rows = 1;
|
_columnsModel.Rows = 1;
|
||||||
_columnsModel.RowPercents = new int[1] { c_multiplier };
|
_columnsModel.RowPercents = new int[1] { c_multiplier };
|
||||||
_defaultModels.Add(_columnsModel);
|
_defaultModels.Add(_columnsModel);
|
||||||
|
|
||||||
_rowsModel = new GridLayoutModel("Rows", c_rowsModelId);
|
_rowsModel = new GridLayoutModel("Rows", c_rowsModelId);
|
||||||
_rowsModel.Columns = 1;
|
_rowsModel.Columns = 1;
|
||||||
_rowsModel.ColumnPercents = new int[1] { c_multiplier };
|
_rowsModel.ColumnPercents = new int[1] { c_multiplier };
|
||||||
_defaultModels.Add(_rowsModel);
|
_defaultModels.Add(_rowsModel);
|
||||||
|
|
||||||
_gridModel = new GridLayoutModel("Grid", c_gridModelId);
|
_gridModel = new GridLayoutModel("Grid", c_gridModelId);
|
||||||
_defaultModels.Add(_gridModel);
|
_defaultModels.Add(_gridModel);
|
||||||
|
|
||||||
_priorityGridModel = new GridLayoutModel("Priority Grid", c_priorityGridModelId);
|
_priorityGridModel = new GridLayoutModel("Priority Grid", c_priorityGridModelId);
|
||||||
_defaultModels.Add(_priorityGridModel);
|
_defaultModels.Add(_priorityGridModel);
|
||||||
|
|
||||||
_blankCustomModel = new CanvasLayoutModel("Create new custom", c_blankCustomModelId, (int)workArea.Width, (int)workArea.Height);
|
_blankCustomModel = new CanvasLayoutModel("Create new custom", c_blankCustomModelId, (int)_workArea.Width, (int)_workArea.Height);
|
||||||
|
|
||||||
_zoneCount = (int)Registry.GetValue(FullRegistryPath, "ZoneCount", 3);
|
_zoneCount = (int)Registry.GetValue(_uniqueRegistryPath, "ZoneCount", 3);
|
||||||
_spacing = (int)Registry.GetValue(FullRegistryPath, "Spacing", 16);
|
_spacing = (int)Registry.GetValue(_uniqueRegistryPath, "Spacing", 16);
|
||||||
_showSpacing = (int)Registry.GetValue(FullRegistryPath, "ShowSpacing", 1) == 1;
|
_showSpacing = (int)Registry.GetValue(_uniqueRegistryPath, "ShowSpacing", 1) == 1;
|
||||||
|
|
||||||
UpdateLayoutModels();
|
UpdateLayoutModels();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ZoneCount - number of zones selected in the picker window
|
// ZoneCount - number of zones selected in the picker window
|
||||||
public int ZoneCount
|
public int ZoneCount
|
||||||
{
|
{
|
||||||
get { return _zoneCount; }
|
get { return _zoneCount; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_zoneCount != value)
|
if (_zoneCount != value)
|
||||||
{
|
{
|
||||||
_zoneCount = value;
|
_zoneCount = value;
|
||||||
Registry.SetValue(FullRegistryPath, "ZoneCount", _zoneCount, RegistryValueKind.DWord);
|
Registry.SetValue(_uniqueRegistryPath, "ZoneCount", _zoneCount, RegistryValueKind.DWord);
|
||||||
UpdateLayoutModels();
|
UpdateLayoutModels();
|
||||||
FirePropertyChanged("ZoneCount");
|
FirePropertyChanged("ZoneCount");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private int _zoneCount;
|
private int _zoneCount;
|
||||||
|
|
||||||
// Spacing - how much space in between zones of the grid do you want
|
// Spacing - how much space in between zones of the grid do you want
|
||||||
public int Spacing
|
public int Spacing
|
||||||
{
|
{
|
||||||
get { return _spacing; }
|
get { return _spacing; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_spacing != value)
|
if (_spacing != value)
|
||||||
{
|
{
|
||||||
_spacing = value;
|
_spacing = value;
|
||||||
Registry.SetValue(FullRegistryPath, "Spacing", _spacing, RegistryValueKind.DWord);
|
Registry.SetValue(_uniqueRegistryPath, "Spacing", _spacing, RegistryValueKind.DWord);
|
||||||
FirePropertyChanged("Spacing");
|
FirePropertyChanged("Spacing");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private int _spacing;
|
private int _spacing;
|
||||||
|
|
||||||
// ShowSpacing - is the Spacing value used or ignored?
|
// ShowSpacing - is the Spacing value used or ignored?
|
||||||
public bool ShowSpacing
|
public bool ShowSpacing
|
||||||
{
|
{
|
||||||
get { return _showSpacing; }
|
get { return _showSpacing; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_showSpacing != value)
|
if (_showSpacing != value)
|
||||||
{
|
{
|
||||||
_showSpacing = value;
|
_showSpacing = value;
|
||||||
Registry.SetValue(FullRegistryPath, "ShowSpacing", _showSpacing, RegistryValueKind.DWord);
|
Registry.SetValue(_uniqueRegistryPath, "ShowSpacing", _showSpacing, RegistryValueKind.DWord);
|
||||||
FirePropertyChanged("ShowSpacing");
|
FirePropertyChanged("ShowSpacing");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private bool _showSpacing;
|
private bool _showSpacing;
|
||||||
|
|
||||||
// IsShiftKeyPressed - is the shift key currently being held down
|
// IsShiftKeyPressed - is the shift key currently being held down
|
||||||
public bool IsShiftKeyPressed
|
public bool IsShiftKeyPressed
|
||||||
{
|
{
|
||||||
get { return _isShiftKeyPressed; }
|
get { return _isShiftKeyPressed; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_isShiftKeyPressed != value)
|
if (_isShiftKeyPressed != value)
|
||||||
{
|
{
|
||||||
_isShiftKeyPressed = value;
|
_isShiftKeyPressed = value;
|
||||||
FirePropertyChanged("IsShiftKeyPressed");
|
FirePropertyChanged("IsShiftKeyPressed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private bool _isShiftKeyPressed;
|
private bool _isShiftKeyPressed;
|
||||||
|
|
||||||
// IsCtrlKeyPressed - is the ctrl key currently being held down
|
// IsCtrlKeyPressed - is the ctrl key currently being held down
|
||||||
public bool IsCtrlKeyPressed
|
public bool IsCtrlKeyPressed
|
||||||
{
|
{
|
||||||
get { return _isCtrlKeyPressed; }
|
get { return _isCtrlKeyPressed; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_isCtrlKeyPressed != value)
|
if (_isCtrlKeyPressed != value)
|
||||||
{
|
{
|
||||||
_isCtrlKeyPressed = value;
|
_isCtrlKeyPressed = value;
|
||||||
FirePropertyChanged("IsCtrlKeyPressed");
|
FirePropertyChanged("IsCtrlKeyPressed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private bool _isCtrlKeyPressed;
|
private bool _isCtrlKeyPressed;
|
||||||
|
|
||||||
// UpdateLayoutModels
|
public Rect WorkArea
|
||||||
// Update the five default layouts based on the new ZoneCount
|
{
|
||||||
private void UpdateLayoutModels()
|
get { return _workArea; }
|
||||||
{
|
}
|
||||||
int previousZoneCount = _focusModel.Zones.Count;
|
private Rect _workArea;
|
||||||
|
|
||||||
// Update the "Focus" Default Layout
|
public static uint Monitor
|
||||||
_focusModel.Zones.Clear();
|
{
|
||||||
|
get { return _monitor; }
|
||||||
Int32Rect focusZoneRect = new Int32Rect((int)(_focusModel.ReferenceWidth * 0.1), (int)(_focusModel.ReferenceHeight * 0.1), (int)(_focusModel.ReferenceWidth * 0.6), (int)(_focusModel.ReferenceHeight * 0.6));
|
}
|
||||||
int focusRectXIncrement = (ZoneCount <= 1) ? 0 : (int)(_focusModel.ReferenceWidth * 0.2) / (ZoneCount - 1);
|
private static uint _monitor;
|
||||||
int focusRectYIncrement = (ZoneCount <= 1) ? 0 : (int)(_focusModel.ReferenceHeight * 0.2) / (ZoneCount - 1);
|
|
||||||
|
public static String UniqueKey
|
||||||
for (int i = 0; i < ZoneCount; i++)
|
{
|
||||||
{
|
get { return _uniqueKey; }
|
||||||
_focusModel.Zones.Add(focusZoneRect);
|
}
|
||||||
focusZoneRect.X += focusRectXIncrement;
|
private static String _uniqueKey;
|
||||||
focusZoneRect.Y += focusRectYIncrement;
|
private String _uniqueRegistryPath;
|
||||||
}
|
|
||||||
|
public static String WorkAreaKey
|
||||||
// Update the "Rows" and "Columns" Default Layouts
|
{
|
||||||
// They can share their model, just transposed
|
get { return _workAreaKey; }
|
||||||
_rowsModel.CellChildMap = new int[ZoneCount, 1];
|
}
|
||||||
_columnsModel.CellChildMap = new int[1, ZoneCount];
|
private static String _workAreaKey;
|
||||||
_rowsModel.Rows = _columnsModel.Columns = ZoneCount;
|
|
||||||
_rowsModel.RowPercents = _columnsModel.ColumnPercents = new int[ZoneCount];
|
public static float Dpi
|
||||||
|
{
|
||||||
for (int i = 0; i < ZoneCount; i++)
|
get { return _dpi; }
|
||||||
{
|
}
|
||||||
_rowsModel.CellChildMap[i, 0] = i;
|
private static float _dpi;
|
||||||
_columnsModel.CellChildMap[0, i] = i;
|
|
||||||
_rowsModel.RowPercents[i] = c_multiplier / ZoneCount; // _columnsModel is sharing the same array
|
// UpdateLayoutModels
|
||||||
}
|
// Update the five default layouts based on the new ZoneCount
|
||||||
|
private void UpdateLayoutModels()
|
||||||
// Update the "Grid" Default Layout
|
{
|
||||||
int rows = 1;
|
int previousZoneCount = _focusModel.Zones.Count;
|
||||||
int cols = 1;
|
|
||||||
int mergeCount = 0;
|
// Update the "Focus" Default Layout
|
||||||
while (ZoneCount / rows >= rows)
|
_focusModel.Zones.Clear();
|
||||||
{
|
|
||||||
rows++;
|
Int32Rect focusZoneRect = new Int32Rect((int)(_focusModel.ReferenceWidth * 0.1), (int)(_focusModel.ReferenceHeight * 0.1), (int)(_focusModel.ReferenceWidth * 0.6), (int)(_focusModel.ReferenceHeight * 0.6));
|
||||||
}
|
int focusRectXIncrement = (ZoneCount <= 1) ? 0 : (int)(_focusModel.ReferenceWidth * 0.2) / (ZoneCount - 1);
|
||||||
rows--;
|
int focusRectYIncrement = (ZoneCount <= 1) ? 0 : (int)(_focusModel.ReferenceHeight * 0.2) / (ZoneCount - 1);
|
||||||
cols = ZoneCount / rows;
|
|
||||||
if (ZoneCount % rows == 0)
|
for (int i = 0; i < ZoneCount; i++)
|
||||||
{
|
{
|
||||||
// even grid
|
_focusModel.Zones.Add(focusZoneRect);
|
||||||
}
|
focusZoneRect.X += focusRectXIncrement;
|
||||||
else
|
focusZoneRect.Y += focusRectYIncrement;
|
||||||
{
|
}
|
||||||
cols++;
|
|
||||||
mergeCount = rows - (ZoneCount % rows);
|
// Update the "Rows" and "Columns" Default Layouts
|
||||||
}
|
// They can share their model, just transposed
|
||||||
_gridModel.Rows = rows;
|
_rowsModel.CellChildMap = new int[ZoneCount, 1];
|
||||||
_gridModel.Columns = cols;
|
_columnsModel.CellChildMap = new int[1, ZoneCount];
|
||||||
_gridModel.RowPercents = new int[rows];
|
_rowsModel.Rows = _columnsModel.Columns = ZoneCount;
|
||||||
_gridModel.ColumnPercents = new int[cols];
|
_rowsModel.RowPercents = _columnsModel.ColumnPercents = new int[ZoneCount];
|
||||||
_gridModel.CellChildMap = new int[rows, cols];
|
|
||||||
|
for (int i = 0; i < ZoneCount; i++)
|
||||||
for (int row = 0; row < rows; row++)
|
{
|
||||||
{
|
_rowsModel.CellChildMap[i, 0] = i;
|
||||||
_gridModel.RowPercents[row] = c_multiplier / rows;
|
_columnsModel.CellChildMap[0, i] = i;
|
||||||
}
|
_rowsModel.RowPercents[i] = c_multiplier / ZoneCount; // _columnsModel is sharing the same array
|
||||||
|
}
|
||||||
for (int col = 0; col < cols; col++)
|
|
||||||
{
|
// Update the "Grid" Default Layout
|
||||||
_gridModel.ColumnPercents[col] = c_multiplier / cols;
|
int rows = 1;
|
||||||
}
|
int cols = 1;
|
||||||
|
int mergeCount = 0;
|
||||||
int index = 0;
|
while (ZoneCount / rows >= rows)
|
||||||
for (int col = cols - 1; col >= 0; col--)
|
{
|
||||||
{
|
rows++;
|
||||||
for (int row = rows - 1; row >= 0; row--)
|
}
|
||||||
{
|
rows--;
|
||||||
_gridModel.CellChildMap[row, col] = index++;
|
cols = ZoneCount / rows;
|
||||||
if (index == ZoneCount)
|
if (ZoneCount % rows == 0)
|
||||||
{
|
{
|
||||||
index--;
|
// even grid
|
||||||
}
|
}
|
||||||
|
else
|
||||||
}
|
{
|
||||||
}
|
cols++;
|
||||||
|
mergeCount = rows - (ZoneCount % rows);
|
||||||
// Update the "Priority Grid" Default Layout
|
}
|
||||||
if (ZoneCount <= s_priorityData.Length)
|
_gridModel.Rows = rows;
|
||||||
{
|
_gridModel.Columns = cols;
|
||||||
_priorityGridModel.Reload(s_priorityData[ZoneCount - 1]);
|
_gridModel.RowPercents = new int[rows];
|
||||||
}
|
_gridModel.ColumnPercents = new int[cols];
|
||||||
else
|
_gridModel.CellChildMap = new int[rows, cols];
|
||||||
{
|
|
||||||
// same as grid;
|
for (int row = 0; row < rows; row++)
|
||||||
_priorityGridModel.Rows = _gridModel.Rows;
|
{
|
||||||
_priorityGridModel.Columns = _gridModel.Columns;
|
_gridModel.RowPercents[row] = c_multiplier / rows;
|
||||||
_priorityGridModel.RowPercents = _gridModel.RowPercents;
|
}
|
||||||
_priorityGridModel.ColumnPercents = _gridModel.ColumnPercents;
|
|
||||||
_priorityGridModel.CellChildMap = _gridModel.CellChildMap;
|
for (int col = 0; col < cols; col++)
|
||||||
}
|
{
|
||||||
}
|
_gridModel.ColumnPercents[col] = c_multiplier / cols;
|
||||||
|
}
|
||||||
public IList<LayoutModel> DefaultModels { get { return _defaultModels; } }
|
|
||||||
public ObservableCollection<LayoutModel> CustomModels
|
int index = 0;
|
||||||
{
|
for (int col = cols - 1; col >= 0; col--)
|
||||||
get
|
{
|
||||||
{
|
for (int row = rows - 1; row >= 0; row--)
|
||||||
if (_customModels == null)
|
{
|
||||||
{
|
_gridModel.CellChildMap[row, col] = index++;
|
||||||
_customModels = LayoutModel.LoadCustomModels();
|
if (index == ZoneCount)
|
||||||
_customModels.Insert(0, _blankCustomModel);
|
{
|
||||||
}
|
index--;
|
||||||
return _customModels;
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
private ObservableCollection<LayoutModel> _customModels;
|
}
|
||||||
|
|
||||||
public static readonly string RegistryPath = "SOFTWARE\\SuperFancyZones";
|
// Update the "Priority Grid" Default Layout
|
||||||
public static readonly string FullRegistryPath = "HKEY_CURRENT_USER\\" + RegistryPath;
|
if (ZoneCount <= s_priorityData.Length)
|
||||||
|
{
|
||||||
public static bool IsPredefinedLayout(LayoutModel model)
|
_priorityGridModel.Reload(s_priorityData[ZoneCount - 1]);
|
||||||
{
|
}
|
||||||
return (model.Id >= c_lastPrefinedId);
|
else
|
||||||
}
|
{
|
||||||
|
// same as grid;
|
||||||
// implementation of INotifyProeprtyChanged
|
_priorityGridModel.Rows = _gridModel.Rows;
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
_priorityGridModel.Columns = _gridModel.Columns;
|
||||||
|
_priorityGridModel.RowPercents = _gridModel.RowPercents;
|
||||||
// FirePropertyChanged -- wrapper that calls INPC.PropertyChanged
|
_priorityGridModel.ColumnPercents = _gridModel.ColumnPercents;
|
||||||
protected virtual void FirePropertyChanged(string propertyName)
|
_priorityGridModel.CellChildMap = _gridModel.CellChildMap;
|
||||||
{
|
}
|
||||||
PropertyChangedEventHandler handler = PropertyChanged;
|
}
|
||||||
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
private void ParseCommandLineArgs()
|
||||||
|
{
|
||||||
// storage for Default Layout Models
|
_workArea = System.Windows.SystemParameters.WorkArea;
|
||||||
private IList<LayoutModel> _defaultModels;
|
_monitor = 0;
|
||||||
private CanvasLayoutModel _focusModel;
|
_uniqueRegistryPath = FullRegistryPath;
|
||||||
private GridLayoutModel _rowsModel;
|
_uniqueKey = "";
|
||||||
private GridLayoutModel _columnsModel;
|
_dpi = 1;
|
||||||
private GridLayoutModel _gridModel;
|
|
||||||
private GridLayoutModel _priorityGridModel;
|
string[] args = Environment.GetCommandLineArgs();
|
||||||
private CanvasLayoutModel _blankCustomModel;
|
if (args.Length == 7)
|
||||||
|
{
|
||||||
private static readonly ushort c_focusModelId = 0xFFFF;
|
// 1 = unique key for per-monitor settings
|
||||||
private static readonly ushort c_rowsModelId = 0xFFFE;
|
// 2 = layoutid used to generate current layout (used to pick the default layout to show)
|
||||||
private static readonly ushort c_columnsModelId = 0xFFFD;
|
// 3 = handle to monitor (passed back to engine to persist data)
|
||||||
private static readonly ushort c_gridModelId = 0xFFFC;
|
// 4 = X_Y_Width_Height (where EditorOverlay shows up)
|
||||||
private static readonly ushort c_priorityGridModelId = 0xFFFB;
|
// 5 = resolution key (passed back to engine to persist data)
|
||||||
private static readonly ushort c_blankCustomModelId = 0xFFFA;
|
// 6 = monitor DPI (float)
|
||||||
private static readonly ushort c_lastPrefinedId = c_blankCustomModelId;
|
|
||||||
|
_uniqueKey = args[1];
|
||||||
// hard coded data for all the "Priority Grid" configurations that are unique to "Grid"
|
_uniqueRegistryPath += "\\" + _uniqueKey;
|
||||||
private static byte[][] s_priorityData = new byte[][]
|
|
||||||
{
|
var parsedLocation = args[4].Split('_');
|
||||||
new byte[] { 0, 0, 0, 0, 0, 1, 1, 39, 16, 39, 16, 0 },
|
var x = int.Parse(parsedLocation[0]);
|
||||||
new byte[] { 0, 0, 0, 0, 0, 1, 2, 39, 16, 26, 11, 13, 5, 0, 1 },
|
var y = int.Parse(parsedLocation[1]);
|
||||||
new byte[] { 0, 0, 0, 0, 0, 1, 3, 39, 16, 9, 196, 19, 136, 9, 196, 0, 1, 2 },
|
var width = int.Parse(parsedLocation[2]);
|
||||||
new byte[] { 0, 0, 0, 0, 0, 2, 3, 19, 136, 19, 136, 9, 196, 19, 136, 9, 196, 0, 1, 2, 0, 1, 3 },
|
var height = int.Parse(parsedLocation[3]);
|
||||||
new byte[] { 0, 0, 0, 0, 0, 2, 3, 19, 136, 19, 136, 9, 196, 19, 136, 9, 196, 0, 1, 2, 3, 1, 4 },
|
|
||||||
new byte[] { 0, 0, 0, 0, 0, 3, 3, 13, 5, 13, 6, 13, 5, 9, 196, 19, 136, 9, 196, 0, 1, 2, 0, 1, 3, 4, 1, 5 },
|
_workAreaKey = args[5];
|
||||||
new byte[] { 0, 0, 0, 0, 0, 3, 3, 13, 5, 13, 6, 13, 5, 9, 196, 19, 136, 9, 196, 0, 1, 2, 3, 1, 4, 5, 1, 6 },
|
_dpi = float.Parse(args[6]);
|
||||||
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 2, 5, 6, 1, 2, 7 },
|
_workArea = new Rect(x, y, width, height);
|
||||||
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 2, 5, 6, 1, 7, 8 },
|
|
||||||
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 5, 6, 7, 1, 8, 9 },
|
uint monitor = 0;
|
||||||
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 5, 6, 7, 8, 9, 10 }
|
if (uint.TryParse(args[4], out monitor))
|
||||||
};
|
{
|
||||||
|
_monitor = monitor;
|
||||||
private const int c_multiplier = 10000;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public IList<LayoutModel> DefaultModels { get { return _defaultModels; } }
|
||||||
|
public ObservableCollection<LayoutModel> CustomModels
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_customModels == null)
|
||||||
|
{
|
||||||
|
_customModels = LayoutModel.LoadCustomModels();
|
||||||
|
_customModels.Insert(0, _blankCustomModel);
|
||||||
|
}
|
||||||
|
return _customModels;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private ObservableCollection<LayoutModel> _customModels;
|
||||||
|
|
||||||
|
public static readonly string RegistryPath = "SOFTWARE\\SuperFancyZones";
|
||||||
|
public static readonly string FullRegistryPath = "HKEY_CURRENT_USER\\" + RegistryPath;
|
||||||
|
|
||||||
|
public static bool IsPredefinedLayout(LayoutModel model)
|
||||||
|
{
|
||||||
|
return (model.Id >= c_lastPrefinedId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// implementation of INotifyProeprtyChanged
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
// FirePropertyChanged -- wrapper that calls INPC.PropertyChanged
|
||||||
|
protected virtual void FirePropertyChanged(string propertyName)
|
||||||
|
{
|
||||||
|
PropertyChangedEventHandler handler = PropertyChanged;
|
||||||
|
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
|
||||||
|
// storage for Default Layout Models
|
||||||
|
private IList<LayoutModel> _defaultModels;
|
||||||
|
private CanvasLayoutModel _focusModel;
|
||||||
|
private GridLayoutModel _rowsModel;
|
||||||
|
private GridLayoutModel _columnsModel;
|
||||||
|
private GridLayoutModel _gridModel;
|
||||||
|
private GridLayoutModel _priorityGridModel;
|
||||||
|
private CanvasLayoutModel _blankCustomModel;
|
||||||
|
|
||||||
|
private static readonly ushort c_focusModelId = 0xFFFF;
|
||||||
|
private static readonly ushort c_rowsModelId = 0xFFFE;
|
||||||
|
private static readonly ushort c_columnsModelId = 0xFFFD;
|
||||||
|
private static readonly ushort c_gridModelId = 0xFFFC;
|
||||||
|
private static readonly ushort c_priorityGridModelId = 0xFFFB;
|
||||||
|
private static readonly ushort c_blankCustomModelId = 0xFFFA;
|
||||||
|
private static readonly ushort c_lastPrefinedId = c_blankCustomModelId;
|
||||||
|
|
||||||
|
// hard coded data for all the "Priority Grid" configurations that are unique to "Grid"
|
||||||
|
private static byte[][] s_priorityData = new byte[][]
|
||||||
|
{
|
||||||
|
new byte[] { 0, 0, 0, 0, 0, 1, 1, 39, 16, 39, 16, 0 },
|
||||||
|
new byte[] { 0, 0, 0, 0, 0, 1, 2, 39, 16, 26, 11, 13, 5, 0, 1 },
|
||||||
|
new byte[] { 0, 0, 0, 0, 0, 1, 3, 39, 16, 9, 196, 19, 136, 9, 196, 0, 1, 2 },
|
||||||
|
new byte[] { 0, 0, 0, 0, 0, 2, 3, 19, 136, 19, 136, 9, 196, 19, 136, 9, 196, 0, 1, 2, 0, 1, 3 },
|
||||||
|
new byte[] { 0, 0, 0, 0, 0, 2, 3, 19, 136, 19, 136, 9, 196, 19, 136, 9, 196, 0, 1, 2, 3, 1, 4 },
|
||||||
|
new byte[] { 0, 0, 0, 0, 0, 3, 3, 13, 5, 13, 6, 13, 5, 9, 196, 19, 136, 9, 196, 0, 1, 2, 0, 1, 3, 4, 1, 5 },
|
||||||
|
new byte[] { 0, 0, 0, 0, 0, 3, 3, 13, 5, 13, 6, 13, 5, 9, 196, 19, 136, 9, 196, 0, 1, 2, 3, 1, 4, 5, 1, 6 },
|
||||||
|
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 2, 5, 6, 1, 2, 7 },
|
||||||
|
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 2, 5, 6, 1, 7, 8 },
|
||||||
|
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 5, 6, 7, 1, 8, 9 },
|
||||||
|
new byte[] { 0, 0, 0, 0, 0, 3, 4, 13, 5, 13, 6, 13, 5, 9, 196, 9, 196, 9, 196, 9, 196, 0, 1, 2, 3, 4, 1, 5, 6, 7, 8, 9, 10 }
|
||||||
|
};
|
||||||
|
|
||||||
|
private const int c_multiplier = 10000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include "pch.h"
|
#include "pch.h"
|
||||||
|
#include "common/dpi_aware.h"
|
||||||
|
|
||||||
struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZonesCallback, IZoneWindowHost>
|
struct FancyZones : public winrt::implements<FancyZones, IFancyZones, IFancyZonesCallback, IZoneWindowHost>
|
||||||
{
|
{
|
||||||
@ -237,18 +238,43 @@ void FancyZones::ToggleEditor() noexcept
|
|||||||
m_terminateEditorEvent.reset(CreateEvent(nullptr, true, false, nullptr));
|
m_terminateEditorEvent.reset(CreateEvent(nullptr, true, false, nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: multimon support
|
const HWND foregroundWindow = GetForegroundWindow();
|
||||||
// Pass in args so that the editor shows up on the correct monitor
|
if (const HMONITOR monitor = MonitorFromWindow(foregroundWindow, MONITOR_DEFAULTTOPRIMARY))
|
||||||
// This can be an HWND, HMONITOR, or the X/Y/Width/Height of the monitor's work area, (whichever works best).
|
|
||||||
if (const HMONITOR monitor = MonitorFromWindow(nullptr, MONITOR_DEFAULTTOPRIMARY))
|
|
||||||
{
|
{
|
||||||
std::shared_lock readLock(m_lock);
|
std::shared_lock readLock(m_lock);
|
||||||
auto iter = m_zoneWindowMap.find(monitor);
|
auto iter = m_zoneWindowMap.find(monitor);
|
||||||
if (iter != m_zoneWindowMap.end())
|
if (iter != m_zoneWindowMap.end())
|
||||||
{
|
{
|
||||||
// Pass command line args to the editor to tell it which layout it should pick by default
|
UINT dpi_x = 96;
|
||||||
auto activeZoneSet = iter->second->ActiveZoneSet();
|
UINT dpi_y = 96;
|
||||||
std::wstring params = iter->second->UniqueId() + L" " + std::to_wstring(activeZoneSet->LayoutId());
|
DPIAware::GetScreenDPIForWindow(foregroundWindow, dpi_x, dpi_y);
|
||||||
|
|
||||||
|
MONITORINFOEX mi;
|
||||||
|
mi.cbSize = sizeof(mi);
|
||||||
|
GetMonitorInfo(monitor, &mi);
|
||||||
|
|
||||||
|
// X/Y need to start in unscaled screen coordinates to get to the proper top/left of the monitor
|
||||||
|
// From there, we need to scale the difference between the monitor and workarea rects to get the
|
||||||
|
// appropriate offset where the overlay should appear.
|
||||||
|
// This covers the cases where the taskbar is not at the bottom of the screen.
|
||||||
|
const auto x = mi.rcMonitor.left + MulDiv(mi.rcWork.left - mi.rcMonitor.left, 96, dpi_x);
|
||||||
|
const auto y = mi.rcMonitor.top + MulDiv(mi.rcWork.top - mi.rcMonitor.top, 96, dpi_y);
|
||||||
|
|
||||||
|
// Location that the editor should occupy, scaled by DPI
|
||||||
|
std::wstring editorLocation =
|
||||||
|
std::to_wstring(x) + L"_" +
|
||||||
|
std::to_wstring(y) + L"_" +
|
||||||
|
std::to_wstring(MulDiv(mi.rcWork.right - mi.rcWork.left, 96, dpi_x)) + L"_" +
|
||||||
|
std::to_wstring(MulDiv(mi.rcWork.bottom - mi.rcWork.top, 96, dpi_y));
|
||||||
|
|
||||||
|
const std::wstring params =
|
||||||
|
iter->second->UniqueId() + L" " +
|
||||||
|
std::to_wstring(iter->second->ActiveZoneSet()->LayoutId()) + L" " +
|
||||||
|
std::to_wstring(reinterpret_cast<UINT_PTR>(monitor)) + L" " +
|
||||||
|
editorLocation + L" " +
|
||||||
|
iter->second->WorkAreaKey() + L" " +
|
||||||
|
std::to_wstring(static_cast<float>(dpi_x) / 96.0f);
|
||||||
|
|
||||||
SHELLEXECUTEINFO sei{ sizeof(sei) };
|
SHELLEXECUTEINFO sei{ sizeof(sei) };
|
||||||
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
sei.fMask = { SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_NO_UI };
|
||||||
sei.lpFile = L"modules\\FancyZonesEditor.exe";
|
sei.lpFile = L"modules\\FancyZonesEditor.exe";
|
||||||
|
@ -18,6 +18,7 @@ public:
|
|||||||
IFACEMETHODIMP_(void) CycleActiveZoneSet(DWORD vkCode) noexcept;
|
IFACEMETHODIMP_(void) CycleActiveZoneSet(DWORD vkCode) noexcept;
|
||||||
IFACEMETHODIMP_(std::wstring) DeviceId() noexcept { return { m_deviceId.get() }; }
|
IFACEMETHODIMP_(std::wstring) DeviceId() noexcept { return { m_deviceId.get() }; }
|
||||||
IFACEMETHODIMP_(std::wstring) UniqueId() noexcept { return { m_uniqueId }; }
|
IFACEMETHODIMP_(std::wstring) UniqueId() noexcept { return { m_uniqueId }; }
|
||||||
|
IFACEMETHODIMP_(std::wstring) WorkAreaKey() noexcept { return { m_workArea }; }
|
||||||
IFACEMETHODIMP_(void) SaveWindowProcessToZoneIndex(HWND window) noexcept;
|
IFACEMETHODIMP_(void) SaveWindowProcessToZoneIndex(HWND window) noexcept;
|
||||||
IFACEMETHODIMP_(IZoneSet*) ActiveZoneSet() noexcept { return m_activeZoneSet.get(); }
|
IFACEMETHODIMP_(IZoneSet*) ActiveZoneSet() noexcept { return m_activeZoneSet.get(); }
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@ interface __declspec(uuid("{7F017528-8110-4FB3-BE41-F472969C2560}")) IZoneWindow
|
|||||||
IFACEMETHOD_(void, SaveWindowProcessToZoneIndex)(HWND window) = 0;
|
IFACEMETHOD_(void, SaveWindowProcessToZoneIndex)(HWND window) = 0;
|
||||||
IFACEMETHOD_(std::wstring, DeviceId)() = 0;
|
IFACEMETHOD_(std::wstring, DeviceId)() = 0;
|
||||||
IFACEMETHOD_(std::wstring, UniqueId)() = 0;
|
IFACEMETHOD_(std::wstring, UniqueId)() = 0;
|
||||||
|
IFACEMETHOD_(std::wstring, WorkAreaKey)() = 0;
|
||||||
IFACEMETHOD_(IZoneSet*, ActiveZoneSet)() = 0;
|
IFACEMETHOD_(IZoneSet*, ActiveZoneSet)() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user