Skip to content

Commit

Permalink
Merge pull request #25 from James-LG/james/margin
Browse files Browse the repository at this point in the history
feat: Add per-application margin settings
  • Loading branch information
James-LG authored Oct 27, 2024
2 parents 0d94b92 + aa83955 commit 05d2dbc
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 30 deletions.
29 changes: 29 additions & 0 deletions src/AutoCursorLock.App/Models/BorderDimensionsExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright (c) James La Novara-Gsell. All Rights Reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

namespace AutoCursorLock.App.Models;

using AutoCursorLock.Native;
using AutoCursorLock.Sdk.Models;

/// <summary>
/// Extensions for <see cref="BorderDimensions"/>.
/// </summary>
internal static class BorderDimensionsExtensions
{
/// <summary>
/// Applies a margin to the border dimensions.
/// </summary>
/// <param name="dimensions">The dimensions to adjust.</param>
/// <param name="margin">The margin to apply.</param>
/// <returns>The adjusted dimensions.</returns>
public static BorderDimensions ApplyMargin(this BorderDimensions dimensions, AppLockMargin margin)
{
return new BorderDimensions(
dimensions.Top + margin.Top,
dimensions.Bottom - margin.Bottom,
dimensions.Left + margin.Left,
dimensions.Right - margin.Right
);
}
}
9 changes: 8 additions & 1 deletion src/AutoCursorLock.App/Models/ProcessListItem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ public record ProcessListItem
/// <param name="name">The name of the process.</param>
/// <param name="path">The path of the proceess' executable.</param>
/// <param name="appLockType">The type of app lock.</param>
/// <param name="margin">The margin around the window for the app lock.</param>
/// <param name="icon">The icon image of the process.</param>
public ProcessListItem(string name, string? path, AppLockType appLockType, BitmapSource? icon)
public ProcessListItem(string name, string? path, AppLockType appLockType, AppLockMargin? margin, BitmapSource? icon)
{
Name = name ?? throw new ArgumentNullException(nameof(name));
Path = path;
AppLockType = appLockType;
Margin = margin ?? new AppLockMargin(0, 0, 0, 0);
Icon = icon;
}

Expand All @@ -42,6 +44,11 @@ public ProcessListItem(string name, string? path, AppLockType appLockType, Bitma
/// </summary>
public AppLockType AppLockType { get; init; }

/// <summary>
/// Gets the margin around the window for the app lock.
/// </summary>
public AppLockMargin Margin { get; init; }

/// <summary>
/// Gets the icon image of the process.
/// </summary>
Expand Down
26 changes: 11 additions & 15 deletions src/AutoCursorLock.App/Models/ProcessListItemExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,23 @@ internal static class ProcessListItemExtensions
public static ProcessListItem FromPath(string path)
{
var process = Process.GetProcessesByName(Path.GetFileNameWithoutExtension(path))
.FirstOrDefault()
?? throw new AutoCursorLockException($"Could not find process for path: {path}");
.FirstOrDefault()
?? throw new AutoCursorLockException($"Could not find process for path: {path}");

return FromNameAndPath(process.ProcessName, path);
return FromAppLockSettings(new AppLockSettingsModel(process.ProcessName, path, AppLockType.Window, Margin: default));
}

/// <summary>
/// Creates a <see cref="ProcessListItem"/> from a name and path.
/// </summary>
/// <param name="name">The process' name.</param>
/// <param name="path">The process' path.</param>
/// <param name="appLockSettings">The app lock settings.</param>
/// <returns>The process list item.</returns>
public static ProcessListItem FromNameAndPath(string name, string? path)
public static ProcessListItem FromAppLockSettings(AppLockSettingsModel appLockSettings)
{
var bitmapIcon = default(BitmapSource?);
if (path is not null)
if (appLockSettings.Path is not null && File.Exists(appLockSettings.Path))
{
using var icon = System.Drawing.Icon.ExtractAssociatedIcon(path);
using var icon = System.Drawing.Icon.ExtractAssociatedIcon(appLockSettings.Path);
bitmapIcon = icon is null
? null
: Imaging.CreateBitmapSourceFromHIcon(icon.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
Expand All @@ -53,7 +52,7 @@ public static ProcessListItem FromNameAndPath(string name, string? path)
bitmapIcon = new BitmapImage(new Uri("pack://application:,,,/media/question-mark.png", UriKind.Absolute));
}

return new ProcessListItem(name, path, AppLockType.Window, bitmapIcon);
return new ProcessListItem(appLockSettings.Name, appLockSettings.Path, appLockSettings.Type, appLockSettings.Margin, bitmapIcon);
}

/// <summary>
Expand All @@ -66,7 +65,8 @@ public static AppLockSettingsModel ToModel(this ProcessListItem processListItem)
return new AppLockSettingsModel(
processListItem.Name,
processListItem.Path,
processListItem.AppLockType
processListItem.AppLockType,
processListItem.Margin
);
}

Expand All @@ -77,10 +77,6 @@ public static AppLockSettingsModel ToModel(this ProcessListItem processListItem)
/// <returns>The process list item.</returns>
public static ProcessListItem ToViewModel(AppLockSettingsModel appLockSettingsModel)
{
var processListItem = FromNameAndPath(appLockSettingsModel.Name, appLockSettingsModel.Path);
return processListItem with
{
AppLockType = appLockSettingsModel.Type
};
return FromAppLockSettings(appLockSettingsModel);
}
}
10 changes: 1 addition & 9 deletions src/AutoCursorLock.App/Models/UserSettingsExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,7 @@ public static ConversionResult<UserSettings> ToViewModel(this UserSettingsModel
{
try
{
ProcessListItem processListItem;
if (File.Exists(appLock.Path))
{
processListItem = ProcessListItemExtensions.FromNameAndPath(appLock.Name, appLock.Path);
}
else
{
processListItem = ProcessListItemExtensions.FromNameAndPath(appLock.Name, default);
}
var processListItem = ProcessListItemExtensions.FromAppLockSettings(appLock);

processes.Add(processListItem);
}
Expand Down
50 changes: 49 additions & 1 deletion src/AutoCursorLock.App/Views/AppLockSettingsWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:AutoCursorLock.App.Views"
mc:Ignorable="d"
Title="App Lock Settings" Height="200" Width="600">
Title="App Lock Settings" Height="300" Width="600">
<Grid x:Name="mainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
Expand Down Expand Up @@ -40,5 +44,49 @@
MinWidth="80"
ItemsSource="{Binding AppLockTypeOptions}"
SelectedItem="{Binding AppLockSettings.AppLockType}" />
<TextBlock
Grid.Column="0"
Grid.Row="1">
Left-side margin
</TextBlock>
<TextBox
Grid.Column="1"
Grid.Row="1"
Margin="5"
MinWidth="80"
Text="{Binding AppLockSettings.Margin.Left}" />
<TextBlock
Grid.Column="0"
Grid.Row="2">
Top-side margin
</TextBlock>
<TextBox
Grid.Column="1"
Grid.Row="2"
Margin="5"
MinWidth="80"
Text="{Binding AppLockSettings.Margin.Top}" />
<TextBlock
Grid.Column="0"
Grid.Row="3">
Right-side margin
</TextBlock>
<TextBox
Grid.Column="1"
Grid.Row="3"
Margin="5"
MinWidth="80"
Text="{Binding AppLockSettings.Margin.Right}" />
<TextBlock
Grid.Column="0"
Grid.Row="4">
Bottom-side margin
</TextBlock>
<TextBox
Grid.Column="1"
Grid.Row="4"
Margin="5"
MinWidth="80"
Text="{Binding AppLockSettings.Margin.Bottom}" />
</Grid>
</Window>
10 changes: 8 additions & 2 deletions src/AutoCursorLock.App/Views/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,12 @@ private void AdjustLock(IntPtr hwnd)
AppLockType.Monitor => ApplicationHandler.GetMonitorBorders(hwnd),
_ => throw new NotImplementedException("Invalid AppLockType")
};

if (ActiveProcess.Margin is not null)
{
border = border.ApplyMargin(ActiveProcess.Margin);
}

if (!MouseHandler.LockCursorToBorder(border))
{
this.logger.LogError("Lock cursor error code {ErrorCode}", Marshal.GetLastWin32Error());
Expand Down Expand Up @@ -304,7 +310,7 @@ private void RefreshButton_Click(object sender, RoutedEventArgs e)
{
if (p.MainWindowHandle != IntPtr.Zero && p.MainModule?.FileName != null)
{
var process = ProcessListItemExtensions.FromNameAndPath(p.ProcessName, p.MainModule.FileName);
var process = ProcessListItemExtensions.FromAppLockSettings(AppLockSettingsModel.FromNameAndPath(p.ProcessName, p.MainModule.FileName));
Processes.Add(process);
}
}
Expand All @@ -314,7 +320,7 @@ private void RefreshButton_Click(object sender, RoutedEventArgs e)

try
{
var process = ProcessListItemExtensions.FromNameAndPath(p.ProcessName, null);
var process = ProcessListItemExtensions.FromAppLockSettings(AppLockSettingsModel.FromNameAndPath(p.ProcessName, path: null));
Processes.Add(process);
}
catch (Exception ex2)
Expand Down
18 changes: 18 additions & 0 deletions src/AutoCursorLock.Sdk/Models/AppLockMargin.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) James La Novara-Gsell. All Rights Reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

namespace AutoCursorLock.Sdk.Models;

/// <summary>
/// Represents the margin around a window for an app lock.
/// </summary>
/// <param name="Left">The left-side margin.</param>
/// <param name="Top">The top-side margin.</param>
/// <param name="Right">The right-side margin.</param>
/// <param name="Bottom">THe bottom-side margin.</param>
public record AppLockMargin(
int Left,
int Top,
int Right,
int Bottom
);
18 changes: 16 additions & 2 deletions src/AutoCursorLock.Sdk/Models/AppLockSettingsModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,22 @@ namespace AutoCursorLock.Sdk.Models;
/// <param name="Name">The name of the process.</param>
/// <param name="Path">The path to the application.</param>
/// <param name="Type">The type of app lock to use.</param>
/// <param name="Margin">The margin around the window for the app lock.</param>
public record AppLockSettingsModel(
string Name,
string? Path,
AppLockType Type
);
AppLockType Type,
AppLockMargin? Margin
)
{
/// <summary>
/// Creates an <see cref="AppLockSettingsModel"/> from the name and path, using defaults for other properties.
/// </summary>
/// <param name="name">The name of the app.</param>
/// <param name="path">The path to the app.</param>
/// <returns>The model.</returns>
public static AppLockSettingsModel FromNameAndPath(string name, string? path)
{
return new AppLockSettingsModel(name, path, AppLockType.Window, new AppLockMargin(0, 0, 0, 0));
}
}

0 comments on commit 05d2dbc

Please sign in to comment.