mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-24 04:00:02 +01:00
Merge branch 'dev/feature/projects' of https://github.com/microsoft/PowerToys into dev/feature/projects
This commit is contained in:
@@ -21,52 +21,120 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ProjectsLauncher", "Project
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProjectsEditor", "ProjectsEditor\ProjectsEditor.csproj", "{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ManagedCommon", "..\..\common\ManagedCommon\ManagedCommon.csproj", "{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PowerToys.Interop", "..\..\common\interop\PowerToys.Interop.vcxproj", "{F055103B-F80B-4D0C-BF48-057C55620033}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ManagedTelemetry", "..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj", "{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Debug|ARM64 = Debug|ARM64
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|Any CPU = Release|Any CPU
|
||||
Release|ARM64 = Release|ARM64
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Debug|x64.Build.0 = Debug|x64
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Debug|x86.Build.0 = Debug|Win32
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Release|Any CPU.Build.0 = Release|x64
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Release|x64.ActiveCfg = Release|x64
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Release|x64.Build.0 = Release|x64
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Release|x86.ActiveCfg = Release|Win32
|
||||
{3D63307B-9D27-44FD-B033-B26F39245B85}.Release|x86.Build.0 = Release|Win32
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Debug|x64.Build.0 = Debug|x64
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Debug|x86.Build.0 = Debug|Win32
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Release|Any CPU.Build.0 = Release|x64
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Release|x64.ActiveCfg = Release|x64
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Release|x64.Build.0 = Release|x64
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Release|x86.ActiveCfg = Release|Win32
|
||||
{2CAC093E-5FCF-4102-9C2C-AC7DD5D9EB96}.Release|x86.Build.0 = Release|Win32
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x64.Build.0 = Debug|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|ARM64.Build.0 = Release|Any CPU
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x64.ActiveCfg = Release|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x64.Build.0 = Release|x64
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{5CCC8468-DEC8-4D36-99D4-5C891BEBD481}.Release|x86.Build.0 = Release|Any CPU
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Debug|x64.Build.0 = Debug|x64
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Debug|x86.Build.0 = Debug|x64
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Release|Any CPU.Build.0 = Release|x64
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Release|x64.ActiveCfg = Release|x64
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Release|x64.Build.0 = Release|x64
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Release|x86.ActiveCfg = Release|x64
|
||||
{A881F6EB-6EDA-4674-A6B7-598F0A8E7048}.Release|x86.Build.0 = Release|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x64.Build.0 = Debug|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Debug|x86.Build.0 = Debug|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|Any CPU.Build.0 = Release|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|x64.ActiveCfg = Release|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|x64.Build.0 = Release|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|x86.ActiveCfg = Release|x64
|
||||
{F055103B-F80B-4D0C-BF48-057C55620033}.Release|x86.Build.0 = Release|x64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Debug|Any CPU.ActiveCfg = Debug|x64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Debug|Any CPU.Build.0 = Debug|x64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Debug|x64.Build.0 = Debug|x64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Debug|x86.Build.0 = Debug|x64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Release|Any CPU.ActiveCfg = Release|x64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Release|Any CPU.Build.0 = Release|x64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Release|x64.ActiveCfg = Release|x64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Release|x64.Build.0 = Release|x64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Release|x86.ActiveCfg = Release|x64
|
||||
{6CE421AD-D249-4BD1-9ADA-B46DA18AADEE}.Release|x86.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using ManagedCommon;
|
||||
using ProjectsEditor.Common;
|
||||
using ProjectsEditor.Utils;
|
||||
using ProjectsEditor.ViewModels;
|
||||
@@ -34,6 +35,8 @@ namespace ProjectsEditor
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += OnUnhandledException;
|
||||
|
||||
Logger.InitializeLogger("\\Projects\\Logs");
|
||||
|
||||
_themeManager = new ThemeManager(this);
|
||||
|
||||
if (_mainViewModel == null)
|
||||
@@ -46,6 +49,7 @@ namespace ProjectsEditor
|
||||
string[] args = Environment.GetCommandLineArgs();
|
||||
if (args != null && args.Length > 1)
|
||||
{
|
||||
Logger.LogInfo($"Started with a parameter: {args[1]}. Trying to launch that project.");
|
||||
_mainViewModel.LaunchProject(args[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,11 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media.Imaging;
|
||||
using ManagedCommon;
|
||||
using Windows.ApplicationModel.Core;
|
||||
using Windows.Management.Deployment;
|
||||
|
||||
namespace ProjectsEditor.Models
|
||||
{
|
||||
@@ -77,10 +81,22 @@ namespace ProjectsEditor.Models
|
||||
{
|
||||
try
|
||||
{
|
||||
_icon = Icon.ExtractAssociatedIcon(AppPath);
|
||||
if (!File.Exists(AppPath) && IsPackagedApp)
|
||||
{
|
||||
Task<AppListEntry> task = Task.Run<AppListEntry>(async () => await GetAppByPackageFamilyNameAsync());
|
||||
AppListEntry packApp = task.Result;
|
||||
string filename = Path.GetFileName(AppPath);
|
||||
string newExeLocation = Path.Combine(packApp.AppInfo.Package.InstalledPath, filename);
|
||||
_icon = Icon.ExtractAssociatedIcon(newExeLocation);
|
||||
}
|
||||
else
|
||||
{
|
||||
_icon = Icon.ExtractAssociatedIcon(AppPath);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError($"Exception while extracting icon from app path: {AppPath}. Exception message: {e.Message}");
|
||||
_icon = new Icon(@"images\DefaultIcon.ico");
|
||||
}
|
||||
}
|
||||
@@ -89,6 +105,31 @@ namespace ProjectsEditor.Models
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<AppListEntry> GetAppByPackageFamilyNameAsync()
|
||||
{
|
||||
var pkgManager = new PackageManager();
|
||||
var pkg = pkgManager.FindPackagesForUser(string.Empty, PackagedId).FirstOrDefault();
|
||||
|
||||
if (pkg == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var apps = await pkg.GetAppListEntriesAsync();
|
||||
if (apps == null || apps.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
AppListEntry firstApp = apps[0];
|
||||
|
||||
// RandomAccessStreamReference stream = firstApp.AppInfo.DisplayInfo.GetLogo(new Windows.Foundation.Size(64, 64));
|
||||
// IRandomAccessStreamWithContentType content = await stream.OpenReadAsync();
|
||||
// BitmapImage bitmapImage = new BitmapImage();
|
||||
// bitmapImage.StreamSource = (Stream)content;
|
||||
return firstApp;
|
||||
}
|
||||
|
||||
private BitmapImage _iconBitmapImage;
|
||||
|
||||
public BitmapImage IconBitmapImage
|
||||
@@ -124,9 +165,9 @@ namespace ProjectsEditor.Models
|
||||
_iconBitmapImage = bitmapImage;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception e)
|
||||
{
|
||||
// todo
|
||||
Logger.LogError($"Exception while drawing icon for app with path: {AppPath}. Exception message: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media.Imaging;
|
||||
using ManagedCommon;
|
||||
using ProjectsEditor.Utils;
|
||||
|
||||
namespace ProjectsEditor.Models
|
||||
@@ -275,8 +276,9 @@ namespace ProjectsEditor.Models
|
||||
{
|
||||
graphics.DrawIcon(app.Icon, new Rectangle(32 * appIndex, 0, 24, 24));
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError($"Exception while drawing the icon for app {Name}. Exception message: {e.Message}");
|
||||
}
|
||||
|
||||
appIndex++;
|
||||
@@ -315,5 +317,27 @@ namespace ProjectsEditor.Models
|
||||
|
||||
return new Rectangle((int)minX, (int)minY, (int)(maxX - minX), (int)(maxY - minY));
|
||||
}
|
||||
|
||||
internal string GetShortcutChars()
|
||||
{
|
||||
if (string.IsNullOrEmpty(Name))
|
||||
{
|
||||
return "PR";
|
||||
}
|
||||
|
||||
string[] words = Name.Trim().ToUpperInvariant().Split(' ');
|
||||
if (words.Length > 2)
|
||||
{
|
||||
return $"{words[0][0]}{words[1][0]}{words[2][0]}";
|
||||
}
|
||||
else if (words.Length == 2)
|
||||
{
|
||||
return $"{words[0][0]}{words[1][0]}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return words[0].Substring(0, Math.Min(3, words[0].Length));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,6 +161,7 @@
|
||||
</Page.Resources>
|
||||
<Grid Margin="40,0,40,40">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
@@ -190,55 +191,56 @@
|
||||
GotFocus="EditNameTextBox_GotFocus"
|
||||
KeyDown="EditNameTextBoxKeyDown" />
|
||||
</StackPanel>
|
||||
<Border
|
||||
Grid.Row="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="{DynamicResource MonitorViewBackgroundBrush}"
|
||||
CornerRadius="5">
|
||||
<ScrollViewer
|
||||
HorizontalAlignment="Center"
|
||||
HorizontalScrollBarVisibility="Auto">
|
||||
<ItemsControl
|
||||
ItemsSource="{Binding Monitors, Mode=OneWay}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel
|
||||
IsItemsHost="True"
|
||||
Orientation="Horizontal"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="models:MonitorSetup">
|
||||
<Grid
|
||||
Margin="20,20,20,20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Text="{Binding MonitorInfoWithResolution}" Foreground="{DynamicResource PrimaryForegroundBrush}" FontSize="16" FontWeight="Normal" Margin="0,5,0,5"/>
|
||||
<Border
|
||||
Grid.Row="1"
|
||||
CornerRadius="5"
|
||||
BorderBrush="{DynamicResource TertiaryBackgroundBrush}"
|
||||
BorderThickness="2"
|
||||
Margin="0,0,0,10">
|
||||
<Image
|
||||
Width="200"
|
||||
Height="140"
|
||||
Source="{Binding PreviewImage, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Stretch="Fill"
|
||||
Margin="2"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
<ScrollViewer
|
||||
Margin="0,10,0,0"
|
||||
VerticalScrollBarVisibility="Auto"
|
||||
Grid.Row="2">
|
||||
Grid.Row="3">
|
||||
<StackPanel Orientation="Vertical">
|
||||
<Border
|
||||
Grid.Row="2"
|
||||
HorizontalAlignment="Stretch"
|
||||
Background="{DynamicResource MonitorViewBackgroundBrush}"
|
||||
CornerRadius="5">
|
||||
<ScrollViewer
|
||||
HorizontalAlignment="Center"
|
||||
HorizontalScrollBarVisibility="Auto">
|
||||
<ItemsControl
|
||||
ItemsSource="{Binding Monitors, Mode=OneWay}">
|
||||
<ItemsControl.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<StackPanel
|
||||
IsItemsHost="True"
|
||||
Orientation="Horizontal"/>
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate DataType="models:MonitorSetup">
|
||||
<Grid
|
||||
Margin="20,20,20,20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Text="{Binding MonitorInfoWithResolution}" Foreground="{DynamicResource PrimaryForegroundBrush}" FontSize="16" FontWeight="Normal" Margin="0,5,0,5"/>
|
||||
<Border
|
||||
Grid.Row="1"
|
||||
CornerRadius="5"
|
||||
BorderBrush="{DynamicResource TertiaryBackgroundBrush}"
|
||||
BorderThickness="2"
|
||||
Margin="0,0,0,10">
|
||||
<Image
|
||||
Width="200"
|
||||
Height="140"
|
||||
Source="{Binding PreviewImage, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Stretch="Fill"
|
||||
Margin="2"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
</Border>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
@@ -251,7 +253,7 @@
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
<DockPanel Grid.Row="3" Margin="0,20,0,20">
|
||||
<DockPanel Grid.Row="4" Margin="0,20,0,20">
|
||||
<CheckBox
|
||||
DockPanel.Dock="Left"
|
||||
Content="{x:Static props:Resources.CreateShortcut}"
|
||||
@@ -266,17 +268,16 @@
|
||||
x:Name="CancelButton"
|
||||
Margin="20,0,0,0"
|
||||
Height="36"
|
||||
Background="{DynamicResource SecondaryBackgroundBrush}"
|
||||
AutomationProperties.Name="{x:Static props:Resources.Cancel}"
|
||||
Click="CancelButtonClicked">
|
||||
<StackPanel Orientation="Horizontal" Margin="12, 2, 12, 0" >
|
||||
<TextBlock
|
||||
AutomationProperties.Name="{x:Static props:Resources.Cancel}"
|
||||
FontFamily="{DynamicResource SymbolThemeFontFamily}"
|
||||
Foreground="{DynamicResource AccentButtonForeground}"
|
||||
Text="" />
|
||||
<TextBlock
|
||||
Margin="12,-4,0,0"
|
||||
Foreground="{DynamicResource AccentButtonForeground}"
|
||||
Text="{x:Static props:Resources.Cancel}" />
|
||||
</StackPanel>
|
||||
<Button.Effect>
|
||||
|
||||
@@ -84,6 +84,12 @@
|
||||
<PackageReference Include="ModernWpfUI" />
|
||||
<PackageReference Include="System.IO.Abstractions" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" />
|
||||
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\..\..\common\ManagedTelemetry\Telemetry\ManagedTelemetry.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="Properties\Resources.Designer.cs">
|
||||
<DesignTime>True</DesignTime>
|
||||
|
||||
@@ -14,12 +14,43 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Media.Media3D;
|
||||
using ModernWpf.Media.Animation;
|
||||
using ProjectsEditor.Models;
|
||||
|
||||
namespace ProjectsEditor.Utils
|
||||
{
|
||||
public class DrawHelper
|
||||
{
|
||||
private const int IconSize = 128;
|
||||
private static Font font = new("Tahoma", 24);
|
||||
private static List<Brush> iconBrushes = new List<Brush>
|
||||
{
|
||||
////Brushes.Gold,
|
||||
////Brushes.SteelBlue,
|
||||
////Brushes.SkyBlue,
|
||||
////Brushes.DarkGoldenrod,
|
||||
////Brushes.ForestGreen,
|
||||
////Brushes.Peru,
|
||||
////Brushes.Chartreuse,
|
||||
////Brushes.LightPink,
|
||||
////Brushes.CadetBlue,
|
||||
////Brushes.DarkSalmon,
|
||||
////Brushes.Orange,
|
||||
////Brushes.DarkSeaGreen,
|
||||
////Brushes.Yellow,
|
||||
////Brushes.Green,
|
||||
////Brushes.Orange,
|
||||
////Brushes.White,
|
||||
new SolidBrush(Color.FromArgb(255, 40, 101, 120)),
|
||||
new SolidBrush(Color.FromArgb(255, 58, 91, 153)),
|
||||
new SolidBrush(Color.FromArgb(255, 87, 88, 163)),
|
||||
new SolidBrush(Color.FromArgb(255, 116, 87, 160)),
|
||||
new SolidBrush(Color.FromArgb(255, 139, 82, 145)),
|
||||
};
|
||||
|
||||
private static int iconBrushIndex;
|
||||
|
||||
public static BitmapImage DrawPreview(Project project, Rectangle bounds)
|
||||
{
|
||||
double scale = 0.1;
|
||||
@@ -132,7 +163,6 @@ namespace ProjectsEditor.Utils
|
||||
if (app.RepeatIndex > 0)
|
||||
{
|
||||
string indexString = app.RepeatIndex.ToString(CultureInfo.InvariantCulture);
|
||||
System.Drawing.Font font = new System.Drawing.Font("Tahoma", 8);
|
||||
int indexSize = (int)(iconBounds.Width * 0.5);
|
||||
Rectangle indexBounds = new Rectangle(iconBounds.Right - indexSize, iconBounds.Bottom - indexSize, indexSize, indexSize);
|
||||
|
||||
@@ -194,7 +224,6 @@ namespace ProjectsEditor.Utils
|
||||
if (app.RepeatIndex > 0)
|
||||
{
|
||||
string indexString = app.RepeatIndex.ToString(CultureInfo.InvariantCulture);
|
||||
System.Drawing.Font font = new System.Drawing.Font("Tahoma", 8);
|
||||
int indexSize = (int)(iconBounds.Width * 0.5);
|
||||
Rectangle indexBounds = new Rectangle(iconBounds.Right - indexSize, iconBounds.Bottom - indexSize, indexSize, indexSize);
|
||||
|
||||
@@ -247,5 +276,169 @@ namespace ProjectsEditor.Utils
|
||||
path.CloseFigure();
|
||||
return path;
|
||||
}
|
||||
|
||||
internal static string CreateShortcutIcon(Project project, out Bitmap bitmap)
|
||||
{
|
||||
object shDesktop = (object)"Desktop";
|
||||
IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell();
|
||||
string shortcutIconFilename = (string)shell.SpecialFolders.Item(ref shDesktop) + $"\\{project.Name}.ico";
|
||||
bitmap = new Bitmap(IconSize, IconSize);
|
||||
using (Graphics graphics = Graphics.FromImage(bitmap))
|
||||
{
|
||||
graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
|
||||
// if (project != null)
|
||||
// {
|
||||
// List<Application> selectedApps = project.Applications.Where(x => x.IsSelected).ToList();
|
||||
// if (selectedApps.Count > 0)
|
||||
// {
|
||||
// graphics.DrawIcon(selectedApps[0].Icon, new Rectangle(0, 0, IconSize / 2, IconSize / 2));
|
||||
// }
|
||||
// if (selectedApps.Count > 1)
|
||||
// {
|
||||
// graphics.DrawIcon(selectedApps[1].Icon, new Rectangle(IconSize / 2, 0, IconSize / 2, IconSize / 2));
|
||||
// }
|
||||
// if (selectedApps.Count > 2)
|
||||
// {
|
||||
// graphics.DrawIcon(selectedApps[2].Icon, new Rectangle(0, IconSize / 2, IconSize / 2, IconSize / 2));
|
||||
// }
|
||||
// if (selectedApps.Count > 3)
|
||||
// {
|
||||
// graphics.DrawIcon(selectedApps[3].Icon, new Rectangle(IconSize / 2, IconSize / 2, IconSize / 2, IconSize / 2));
|
||||
// }
|
||||
// }
|
||||
// graphics.FillRectangle(new System.Drawing.SolidBrush(Color.FromArgb(128, 32, 32, 32)), 0, 0, IconSize, IconSize);
|
||||
graphics.FillEllipse(iconBrushes[iconBrushIndex], 0, 0, IconSize, IconSize);
|
||||
|
||||
string shortcutChars = "PR";
|
||||
|
||||
if (project != null)
|
||||
{
|
||||
shortcutChars = project.GetShortcutChars();
|
||||
}
|
||||
|
||||
Rectangle indexBounds;
|
||||
if (shortcutChars.Length > 1)
|
||||
{
|
||||
indexBounds = new Rectangle(0, 0, IconSize, IconSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
indexBounds = new Rectangle(IconSize / 4, 0, IconSize / 2, IconSize);
|
||||
}
|
||||
|
||||
var textSize = graphics.MeasureString(shortcutChars, font);
|
||||
var state = graphics.Save();
|
||||
graphics.TranslateTransform(indexBounds.Left, indexBounds.Top);
|
||||
graphics.ScaleTransform(indexBounds.Width / textSize.Width, indexBounds.Height / textSize.Height);
|
||||
graphics.DrawString(shortcutChars, font, Brushes.White, PointF.Empty);
|
||||
graphics.Restore(state);
|
||||
iconBrushIndex++;
|
||||
if (iconBrushIndex >= iconBrushes.Count)
|
||||
{
|
||||
iconBrushIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
FileStream fileStream = new FileStream(shortcutIconFilename, FileMode.OpenOrCreate);
|
||||
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
bitmap.Save(memoryStream, ImageFormat.Png);
|
||||
|
||||
BinaryWriter iconWriter = new BinaryWriter(fileStream);
|
||||
if (fileStream != null && iconWriter != null)
|
||||
{
|
||||
// 0-1 reserved, 0
|
||||
iconWriter.Write((byte)0);
|
||||
iconWriter.Write((byte)0);
|
||||
|
||||
// 2-3 image type, 1 = icon, 2 = cursor
|
||||
iconWriter.Write((short)1);
|
||||
|
||||
// 4-5 number of images
|
||||
iconWriter.Write((short)1);
|
||||
|
||||
// image entry 1
|
||||
// 0 image width
|
||||
iconWriter.Write((byte)IconSize);
|
||||
|
||||
// 1 image height
|
||||
iconWriter.Write((byte)IconSize);
|
||||
|
||||
// 2 number of colors
|
||||
iconWriter.Write((byte)0);
|
||||
|
||||
// 3 reserved
|
||||
iconWriter.Write((byte)0);
|
||||
|
||||
// 4-5 color planes
|
||||
iconWriter.Write((short)0);
|
||||
|
||||
// 6-7 bits per pixel
|
||||
iconWriter.Write((short)32);
|
||||
|
||||
// 8-11 size of image data
|
||||
iconWriter.Write((int)memoryStream.Length);
|
||||
|
||||
// 12-15 offset of image data
|
||||
iconWriter.Write((int)(6 + 16));
|
||||
|
||||
// write image data
|
||||
// png data must contain the whole png data file
|
||||
iconWriter.Write(memoryStream.ToArray());
|
||||
|
||||
iconWriter.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
fileStream.Flush();
|
||||
fileStream.Close();
|
||||
return shortcutIconFilename;
|
||||
}
|
||||
|
||||
private static void CreateExamples(Project project)
|
||||
{
|
||||
Bitmap bitmap = new Bitmap(IconSize + 1000, IconSize * iconBrushes.Count);
|
||||
using (Graphics graphics = Graphics.FromImage(bitmap))
|
||||
{
|
||||
for (int brushIndex = 0; brushIndex < iconBrushes.Count; brushIndex++)
|
||||
{
|
||||
graphics.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
||||
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
||||
|
||||
graphics.FillEllipse(iconBrushes[brushIndex], 0, IconSize * brushIndex, IconSize, IconSize);
|
||||
|
||||
string shortcutChars = "PR";
|
||||
|
||||
Rectangle indexBounds;
|
||||
indexBounds = new Rectangle(0, IconSize * brushIndex, IconSize, IconSize);
|
||||
|
||||
var textSize = graphics.MeasureString(shortcutChars, font);
|
||||
var state = graphics.Save();
|
||||
graphics.TranslateTransform(indexBounds.Left, indexBounds.Top);
|
||||
graphics.ScaleTransform(indexBounds.Width / textSize.Width, indexBounds.Height / textSize.Height);
|
||||
graphics.DrawString(shortcutChars, font, Brushes.Black, 0, 0);
|
||||
graphics.Restore(state);
|
||||
|
||||
var b = (SolidBrush)iconBrushes[brushIndex];
|
||||
var colorName = (from p in typeof(System.Drawing.Color).GetProperties()
|
||||
where p.PropertyType.Equals(typeof(System.Drawing.Color))
|
||||
let value = (System.Drawing.Color)p.GetValue(null, null)
|
||||
where value.R == b.Color.R &&
|
||||
value.G == b.Color.G &&
|
||||
value.B == b.Color.B &&
|
||||
value.A == b.Color.A
|
||||
select p.Name).DefaultIfEmpty("unknown").First();
|
||||
|
||||
graphics.DrawString(colorName, font, Brushes.White, IconSize, IconSize * brushIndex);
|
||||
}
|
||||
}
|
||||
|
||||
bitmap.Save(@"C:\temp\shortcutIcons.png");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using ManagedCommon;
|
||||
using ProjectsEditor.Data;
|
||||
using ProjectsEditor.Models;
|
||||
using ProjectsEditor.ViewModels;
|
||||
@@ -25,12 +26,14 @@ namespace ProjectsEditor.Utils
|
||||
ProjectsData parser = new ProjectsData();
|
||||
if (!File.Exists(parser.File))
|
||||
{
|
||||
Logger.LogWarning($"Projects storage file not found: {parser.File}");
|
||||
return new ParsingResult(true);
|
||||
}
|
||||
|
||||
ProjectsData.ProjectsListWrapper projects = parser.Read(parser.File);
|
||||
if (!SetProjects(mainViewModel, projects))
|
||||
{
|
||||
Logger.LogWarning($"Projects storage file content could not be set. Reason: {Properties.Resources.Error_Parsing_Message}");
|
||||
return new ParsingResult(false, ProjectsEditor.Properties.Resources.Error_Parsing_Message);
|
||||
}
|
||||
|
||||
@@ -38,6 +41,7 @@ namespace ProjectsEditor.Utils
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError($"Exception while parsing storage file: {e.Message}");
|
||||
return new ParsingResult(false, e.Message);
|
||||
}
|
||||
}
|
||||
@@ -50,12 +54,14 @@ namespace ProjectsEditor.Utils
|
||||
ProjectsData parser = new ProjectsData();
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
Logger.LogWarning($"ParseProject method. Projects storage file not found: {parser.File}");
|
||||
return new ParsingResult(true);
|
||||
}
|
||||
|
||||
ProjectsData.ProjectsListWrapper projects = parser.Read(fileName);
|
||||
if (!ExtractProject(projects, out project))
|
||||
{
|
||||
Logger.LogWarning($"ParseProject method. Projects storage file content could not be set. Reason: {Properties.Resources.Error_Parsing_Message}");
|
||||
return new ParsingResult(false, ProjectsEditor.Properties.Resources.Error_Parsing_Message);
|
||||
}
|
||||
|
||||
@@ -63,6 +69,7 @@ namespace ProjectsEditor.Utils
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError($"ParseProject method. Exception while parsing storage file: {e.Message}");
|
||||
return new ParsingResult(false, e.Message);
|
||||
}
|
||||
}
|
||||
@@ -209,9 +216,10 @@ namespace ProjectsEditor.Utils
|
||||
IOUtils ioUtils = new IOUtils();
|
||||
ioUtils.WriteFile(serializer.File, serializer.Serialize(projectsWrapper));
|
||||
}
|
||||
catch (Exception)
|
||||
catch (Exception e)
|
||||
{
|
||||
// TODO: show error
|
||||
Logger.LogError($"Exception while writing storage file: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,10 +7,14 @@ using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Timers;
|
||||
using System.Windows.Media.Imaging;
|
||||
using ManagedCommon;
|
||||
using ProjectsEditor.Models;
|
||||
using ProjectsEditor.Utils;
|
||||
using static ProjectsEditor.Data.ProjectsData;
|
||||
@@ -130,17 +134,19 @@ namespace ProjectsEditor.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateShortcut(Project editedProject)
|
||||
private void CreateShortcut(Project project)
|
||||
{
|
||||
object shDesktop = (object)"Desktop";
|
||||
IWshRuntimeLibrary.WshShell shell = new IWshRuntimeLibrary.WshShell();
|
||||
string shortcutAddress = (string)shell.SpecialFolders.Item(ref shDesktop) + $"\\{editedProject.Name}.lnk";
|
||||
string shortcutAddress = (string)shell.SpecialFolders.Item(ref shDesktop) + $"\\{project.Name}.lnk";
|
||||
IWshRuntimeLibrary.IWshShortcut shortcut = (IWshRuntimeLibrary.IWshShortcut)shell.CreateShortcut(shortcutAddress);
|
||||
shortcut.Description = $"Project Launcher {editedProject.Id}";
|
||||
shortcut.Description = $"Project Launcher {project.Id}";
|
||||
string basePath = AppDomain.CurrentDomain.BaseDirectory;
|
||||
shortcut.TargetPath = Path.Combine(basePath, "ProjectsEditor.exe");
|
||||
shortcut.Arguments = '"' + editedProject.Id + '"';
|
||||
shortcut.TargetPath = Path.Combine(basePath, "ProjectsLauncher.exe");
|
||||
shortcut.Arguments = '"' + project.Id + '"';
|
||||
shortcut.WorkingDirectory = basePath;
|
||||
string iconFilename = DrawHelper.CreateShortcutIcon(project, out Bitmap bitmap);
|
||||
shortcut.IconLocation = iconFilename;
|
||||
shortcut.Save();
|
||||
}
|
||||
|
||||
@@ -221,6 +227,7 @@ namespace ProjectsEditor.ViewModels
|
||||
{
|
||||
if (!Projects.Where(x => x.Id == projectId).Any())
|
||||
{
|
||||
Logger.LogWarning($"Project to launch not find. Id: {projectId}");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -237,6 +244,7 @@ namespace ProjectsEditor.ViewModels
|
||||
|
||||
if (exitAfterLaunch)
|
||||
{
|
||||
Logger.LogInfo($"Launched the project {project.Name}. Exiting.");
|
||||
Environment.Exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -144,19 +144,22 @@ namespace Utils
|
||||
};
|
||||
}
|
||||
|
||||
std::wstring installPathUpper(appData.installPath);
|
||||
std::transform(installPathUpper.begin(), installPathUpper.end(), installPathUpper.begin(), towupper);
|
||||
|
||||
if (appPathUpper.contains(installPathUpper))
|
||||
if (!appData.installPath.empty())
|
||||
{
|
||||
return appData;
|
||||
}
|
||||
std::wstring installPathUpper(appData.installPath);
|
||||
std::transform(installPathUpper.begin(), installPathUpper.end(), installPathUpper.begin(), towupper);
|
||||
|
||||
// edge case, some apps (e.g., Gitkraken) have different .exe files in the subfolders.
|
||||
// apps list contains only one path, so in this case app is not found
|
||||
if (std::filesystem::path(appPath).filename() == std::filesystem::path(appData.installPath).filename())
|
||||
{
|
||||
return appData;
|
||||
if (appPathUpper.contains(installPathUpper))
|
||||
{
|
||||
return appData;
|
||||
}
|
||||
|
||||
// edge case, some apps (e.g., Gitkraken) have different .exe files in the subfolders.
|
||||
// apps list contains only one path, so in this case app is not found
|
||||
if (std::filesystem::path(appPath).filename() == std::filesystem::path(appData.installPath).filename())
|
||||
{
|
||||
return appData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ int main(int argc, char* argv[])
|
||||
Project::Application app {
|
||||
.name = data.value().name,
|
||||
.title = title,
|
||||
.path = data.value().installPath,
|
||||
.path = processPath,
|
||||
.packageFullName = data.value().packageFullName,
|
||||
.commandLineArgs = L"",
|
||||
.isMinimized = WindowUtils::IsMinimized(window),
|
||||
|
||||
Reference in New Issue
Block a user