Skip to content

Commit

Permalink
Merge pull request #132 from XanatosX/feature/104_add-posibility-to-p…
Browse files Browse the repository at this point in the history
…osition-app-in-different-screen-corner

[Feature] Implement possiblity to position tool window on different screen corners
  • Loading branch information
XanatosX authored Jan 23, 2024
2 parents 2f35955 + 3eb8136 commit d9d8717
Show file tree
Hide file tree
Showing 15 changed files with 234 additions and 5 deletions.
7 changes: 7 additions & 0 deletions src/ModularToolManager/Models/ApplicationSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Globalization;
using System.Linq;
using System.Text.Json.Serialization;
using ModularToolManager.Enums;

namespace ModularToolManager.Models;

Expand Down Expand Up @@ -61,6 +62,12 @@ public class ApplicationSettings
[JsonPropertyName("search_autocomplete")]
public bool EnableAutocompleteForFunctionSearch { get; set; }

/// <summary>
/// The window position to use by the application. Set to bottom right by default
/// </summary>
[JsonPropertyName("window_position")]
public WindowPositionEnum WindowPosition { get; set; } = WindowPositionEnum.BottomRight;

/// <summary>
/// Create a new instance of this class
/// </summary>
Expand Down
36 changes: 36 additions & 0 deletions src/ModularToolManager/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions src/ModularToolManager/Properties/Resources.de.resx
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,18 @@
<data name="Settings_StartMinimized" xml:space="preserve">
<value>Minimiert starten</value>
</data>
<data name="Settings_WindowPosition_Bottom_Left" xml:space="preserve">
<value>Unten links</value>
</data>
<data name="Settings_WindowPosition_Bottom_Right" xml:space="preserve">
<value>Unten rechts</value>
</data>
<data name="Settings_WindowPosition_Top_Left" xml:space="preserve">
<value>Oben links</value>
</data>
<data name="Settings_WindowPosition_Top_Right" xml:space="preserve">
<value>Oben rechts</value>
</data>
<data name="SubMenu_About" xml:space="preserve">
<value>Über</value>
</data>
Expand Down
12 changes: 12 additions & 0 deletions src/ModularToolManager/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,18 @@
<data name="Settings_StartMinimized" xml:space="preserve">
<value>Start minimized</value>
</data>
<data name="Settings_WindowPosition_Bottom_Left" xml:space="preserve">
<value>Bottom Left</value>
</data>
<data name="Settings_WindowPosition_Bottom_Right" xml:space="preserve">
<value>Bottom Right</value>
</data>
<data name="Settings_WindowPosition_Top_Left" xml:space="preserve">
<value>Top Left</value>
</data>
<data name="Settings_WindowPosition_Top_Right" xml:space="preserve">
<value>Top Right</value>
</data>
<data name="SubMenu_About" xml:space="preserve">
<value>About</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ public class DefaultWindowPositionStrategyFactory : IWindowPositionFactory
return positionEnum switch
{
WindowPositionEnum.BottomRight => new BottomRightStrategy(),
WindowPositionEnum.BottomLeft => new BottomLeftStrategy(),
WindowPositionEnum.TopLeft => new TopLeftStrategy(),
WindowPositionEnum.TopRight => new TopRightStrategy(),
_ => new BottomRightStrategy()
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Platform;

namespace ModularToolManager.Strategies.WindowPosition;


/// </summary>
/// Strategy to position the given window in the bottom left corner of the screen.
/// </summary>
public class BottomLeftStrategy : IWindowPositionStrategy
{
//<inheritdoc/>
public void PositionWindow(Window window, Screen? screen)
{
if (screen is null)
{
return;
}
PixelRect workingArea = screen.WorkingArea;
double newXPos = workingArea.X;
double newYPos = workingArea.Bottom - window.Height;
window.Position = new PixelPoint((int)newXPos, (int)newYPos);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public void PositionWindow(Window window, Screen? screen)
return;
}
PixelRect workingArea = screen.WorkingArea;
double newXPos = workingArea.X + workingArea.Width - window.Width;
double newYPos = workingArea.Y + workingArea.Height - window.Height;
double newXPos = workingArea.Right - window.Width;
double newYPos = workingArea.Bottom - window.Height;
window.Position = new PixelPoint((int)newXPos, (int)newYPos);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Platform;

namespace ModularToolManager.Strategies.WindowPosition;

/// <summary>
/// Position a Window in the bottom left of a given screen
/// </summary>
public class TopLeftStrategy : IWindowPositionStrategy
{
/// <inheritdoc/>
public void PositionWindow(Window window, Screen? screen)
{
if (screen is null )
{
return;
}

PixelRect workingArea = screen.WorkingArea;
double newXPos = workingArea.X;
double newYPos = workingArea.Y;
window.Position = new PixelPoint((int)newXPos, (int)newYPos);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Platform;

namespace ModularToolManager.Strategies.WindowPosition;

/// <summary>
/// Position a Window in the top left of a given screen
/// </summary>
public class TopRightStrategy : IWindowPositionStrategy
{
/// <inheritdoc/>
public void PositionWindow(Window window, Screen? screen)
{
if (screen is null)
{
return;
}

PixelRect workingArea = screen.WorkingArea;
double newXPos = workingArea.Right - window.Width;
double newYPos = workingArea.Y;
window.Position = new PixelPoint((int)newXPos, (int)newYPos);
}
}
26 changes: 26 additions & 0 deletions src/ModularToolManager/ViewModels/SettingsViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
using ModularToolManager.Enums;
using ModularToolManager.Models;
using ModularToolManager.Models.Messages;
using ModularToolManager.Services.Settings;
using ModularToolManager.Services.Ui;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace ModularToolManager.ViewModels;
Expand Down Expand Up @@ -70,6 +72,18 @@ internal partial class SettingsViewModel : ObservableObject
[ObservableProperty]
private bool enableAutocompleteForFunctionSearch;

/// <summary>
/// All the available window positions for the application
/// </summary>
[ObservableProperty]
private ObservableCollection<WindowPositionStrategyViewModel> availableWindowPositions;

/// <summary>
/// The currently selected window position
/// </summary>
[ObservableProperty]
private WindowPositionStrategyViewModel? selectedWindowPosition;

/// <summary>
/// Create a new instance of this class
/// </summary>
Expand All @@ -88,6 +102,17 @@ public SettingsViewModel(ISettingsService settingsService, IThemeService themeSe
.Where(style => !string.IsNullOrEmpty(style.Name))
.Select(style => new ApplicationStyleViewModel(style))
.ToList();


AvailableWindowPositions = new ObservableCollection<WindowPositionStrategyViewModel>();
foreach(var windowPosition in Enum.GetValues(typeof(WindowPositionEnum))
.Cast<WindowPositionEnum>()
.Select(positionEntry => new WindowPositionStrategyViewModel(positionEntry))
.ToList())
{
AvailableWindowPositions.Add(windowPosition);
}
SelectedWindowPosition = AvailableWindowPositions.FirstOrDefault(position => position.WindowPosition == appSettings.WindowPosition) ?? AvailableWindowPositions.FirstOrDefault(entry => entry.WindowPosition == WindowPositionEnum.BottomRight);
SelectedTheme = AvailableThemes.Where(theme => theme.Id == appSettings.SelectedThemeId).FirstOrDefault() ?? AvailableThemes.FirstOrDefault();
EnableAutocompleteForFunctionSearch = appSettings.EnableAutocompleteForFunctionSearch;

Expand Down Expand Up @@ -115,6 +140,7 @@ private void Ok()
settings.ClearSearchAfterFunctionExecute = ClearSearchAfterFunctionExecute;
settings.SelectedThemeId = SelectedTheme?.Id ?? 0;
settings.EnableAutocompleteForFunctionSearch = EnableAutocompleteForFunctionSearch;
settings.WindowPosition = SelectedWindowPosition?.WindowPosition ?? WindowPositionEnum.BottomRight;
});
if (changeResult)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using CommunityToolkit.Mvvm.ComponentModel;
using ModularToolManager.Enums;

namespace ModularToolManager.ViewModels;

/// <summary>
/// View model for the window position strategy
/// </summary>
public partial class WindowPositionStrategyViewModel : ObservableObject
{
/// <summary>
/// The display name of the window position strategy
/// </summary>
[ObservableProperty]
private string displayName;

/// <summary>
/// The stored window position enum
/// </summary>
public WindowPositionEnum WindowPosition {get; init;}

/// <summary>
/// Create a new instance of this class
/// </summary>
/// <param name="windowPositionEnum">The window position enum to create a view model for</param>
public WindowPositionStrategyViewModel(WindowPositionEnum windowPositionEnum)
{
WindowPosition = windowPositionEnum;
DisplayName = windowPositionEnum switch
{
WindowPositionEnum.TopLeft => Properties.Resources.Settings_WindowPosition_Top_Left,
WindowPositionEnum.TopRight => Properties.Resources.Settings_WindowPosition_Top_Right,
WindowPositionEnum.BottomLeft => Properties.Resources.Settings_WindowPosition_Bottom_Left,
WindowPositionEnum.BottomRight => Properties.Resources.Settings_WindowPosition_Bottom_Right,
_ => ""
};
}

}
6 changes: 3 additions & 3 deletions src/ModularToolManager/Views/MainWindow.axaml.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using CommunityToolkit.Mvvm.Messaging;
Expand All @@ -9,7 +8,6 @@
using ModularToolManager.Services.Settings;
using ModularToolManager.Services.Ui;
using System;
using System.Linq;

namespace ModularToolManager.Views;

Expand Down Expand Up @@ -94,6 +92,7 @@ public MainWindow(IWindowManagementService? modalService, ISettingsService? sett
WeakReferenceMessenger.Default.Register<ValueChangedMessage<ApplicationSettings>>(this, (_, settings) =>
{
Topmost = settings.Value.AlwaysOnTop;
PositionWindow();
});
if (settingsService?.GetApplicationSettings().AlwaysOnTop ?? false)
{
Expand Down Expand Up @@ -129,7 +128,8 @@ public override void Show()
/// </summary>
private void PositionWindow()
{
windowPositionFactory?.GetWindowPositionStrategy(WindowPositionEnum.BottomRight)?.PositionWindow(this, Screens.Primary);
var windowPosition = settingsService?.GetApplicationSettings()?.WindowPosition ?? WindowPositionEnum.BottomRight;
windowPositionFactory?.GetWindowPositionStrategy(windowPosition)?.PositionWindow(this, Screens.Primary);
}

/// <inheritdoc/>
Expand Down
1 change: 1 addition & 0 deletions src/ModularToolManager/Views/SettingsView.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
Content="{x:Static p:Resources.Settings_KeepOnTop}"
IsChecked="{Binding TopMost}"
/>
<ComboBox HorizontalAlignment="Stretch" ItemsSource="{Binding AvailableWindowPositions}" SelectedItem="{Binding SelectedWindowPosition}"/>
<CheckBox
Content="{x:Static p:Resources.Settings_CloseOnFunctionExecute}"
IsChecked="{Binding CloseOnFunctionExecute}"
Expand Down
8 changes: 8 additions & 0 deletions src/ModularToolManager/Views/WindowPositionStrategyView.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ModularToolManager.Views.WindowPositionStrategyView">
<TextBlock Text="{Binding DisplayName}" />
</UserControl>
10 changes: 10 additions & 0 deletions src/ModularToolManager/Views/WindowPositionStrategyView.axaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using Avalonia.Controls;

namespace ModularToolManager.Views;
public partial class WindowPositionStrategyView : UserControl
{
public WindowPositionStrategyView()
{
InitializeComponent();
}
}

0 comments on commit d9d8717

Please sign in to comment.