Merge branch 'dev/feature/projects' of https://github.com/microsoft/PowerToys into dev/feature/projects

This commit is contained in:
seraphima
2024-06-10 14:19:34 +02:00
7 changed files with 118 additions and 60 deletions

View File

@@ -51,6 +51,26 @@ namespace ProjectsEditor.Models
public bool Maximized { get; set; } public bool Maximized { get; set; }
private bool _isNotFound;
[JsonIgnore]
public bool IsNotFound
{
get
{
return _isNotFound;
}
set
{
if (_isNotFound != value)
{
_isNotFound = value;
OnPropertyChanged(new PropertyChangedEventArgs(nameof(IsNotFound)));
}
}
}
[JsonIgnore] [JsonIgnore]
public bool IsSelected { get; set; } public bool IsSelected { get; set; }
@@ -85,9 +105,17 @@ namespace ProjectsEditor.Models
{ {
Task<AppListEntry> task = Task.Run<AppListEntry>(async () => await GetAppByPackageFamilyNameAsync()); Task<AppListEntry> task = Task.Run<AppListEntry>(async () => await GetAppByPackageFamilyNameAsync());
AppListEntry packApp = task.Result; AppListEntry packApp = task.Result;
string filename = Path.GetFileName(AppPath); if (packApp == null)
string newExeLocation = Path.Combine(packApp.AppInfo.Package.InstalledPath, filename); {
_icon = Icon.ExtractAssociatedIcon(newExeLocation); IsNotFound = true;
_icon = new Icon(@"images\DefaultIcon.ico");
}
else
{
string filename = Path.GetFileName(AppPath);
string newExeLocation = Path.Combine(packApp.AppInfo.Package.InstalledPath, filename);
_icon = Icon.ExtractAssociatedIcon(newExeLocation);
}
} }
else else
{ {
@@ -97,6 +125,7 @@ namespace ProjectsEditor.Models
catch (Exception e) catch (Exception e)
{ {
Logger.LogError($"Exception while extracting icon from app path: {AppPath}. Exception message: {e.Message}"); Logger.LogError($"Exception while extracting icon from app path: {AppPath}. Exception message: {e.Message}");
IsNotFound = true;
_icon = new Icon(@"images\DefaultIcon.ico"); _icon = new Icon(@"images\DefaultIcon.ico");
} }
} }

View File

@@ -213,6 +213,7 @@ namespace ProjectsEditor.Models
Maximized = item.Maximized, Maximized = item.Maximized,
IsSelected = item.IsSelected, IsSelected = item.IsSelected,
MonitorNumber = item.MonitorNumber, MonitorNumber = item.MonitorNumber,
IsNotFound = item.IsNotFound,
Position = new Application.WindowPosition() { X = item.Position.X, Y = item.Position.Y, Height = item.Position.Height, Width = item.Position.Width }, Position = new Application.WindowPosition() { X = item.Position.X, Y = item.Position.Y, Height = item.Position.Height, Width = item.Position.Width },
Parent = this, Parent = this,
}); });
@@ -246,7 +247,7 @@ namespace ProjectsEditor.Models
public async void Initialize() public async void Initialize()
{ {
PreviewImage = await Task.Run(() => DrawPreviewIcons()); PreviewImage = await Task.Run(() => DrawHelper.DrawPreviewIcons(this));
foreach (MonitorSetup monitor in Monitors) foreach (MonitorSetup monitor in Monitors)
{ {
System.Windows.Rect rect = monitor.MonitorDpiAwareBounds; System.Windows.Rect rect = monitor.MonitorDpiAwareBounds;
@@ -254,53 +255,6 @@ namespace ProjectsEditor.Models
} }
} }
private BitmapImage DrawPreviewIcons()
{
var selectedApps = Applications.Where(x => x.IsSelected);
int appsCount = selectedApps.Count();
if (appsCount == 0)
{
return null;
}
Bitmap previewBitmap = new Bitmap(32 * appsCount, 24);
using (Graphics graphics = Graphics.FromImage(previewBitmap))
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
int appIndex = 0;
foreach (var app in selectedApps)
{
try
{
graphics.DrawIcon(app.Icon, new Rectangle(32 * appIndex, 0, 24, 24));
}
catch (Exception e)
{
Logger.LogError($"Exception while drawing the icon for app {Name}. Exception message: {e.Message}");
}
appIndex++;
}
}
using (var memory = new MemoryStream())
{
previewBitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
}
private Rectangle GetCommonBounds() private Rectangle GetCommonBounds()
{ {
double minX = Monitors.First().MonitorDpiUnawareBounds.Left; double minX = Monitors.First().MonitorDpiUnawareBounds.Left;

View File

@@ -10,6 +10,8 @@
Title="Project Editor" Title="Project Editor"
Background="{DynamicResource PrimaryBackgroundBrush}"> Background="{DynamicResource PrimaryBackgroundBrush}">
<Page.Resources> <Page.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVis" />
<DataTemplate x:Key="headerTemplate"> <DataTemplate x:Key="headerTemplate">
<Border> <Border>
<TextBlock <TextBlock
@@ -28,13 +30,25 @@
MouseLeave="AppBorder_MouseLeave"> MouseLeave="AppBorder_MouseLeave">
<Grid Margin="5"> <Grid Margin="5">
<Grid.ColumnDefinitions> <Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/> <ColumnDefinition Width="*"/>
<ColumnDefinition Width="3*"/> <ColumnDefinition Width="3*"/>
<ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<TextBlock
Text="&#xE945;"
Foreground="Red"
FontSize="14"
FontFamily="{DynamicResource SymbolThemeFontFamily}"
FontWeight="Normal"
Margin="2 0"
ToolTip="{x:Static props:Resources.NotFoundTooltip}"
Visibility="{Binding IsNotFound, Converter={StaticResource BoolToVis}, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
VerticalAlignment="Center"/>
<Image <Image
Grid.Column="1"
Width="20" Width="20"
Height="20" Height="20"
HorizontalAlignment="Center" HorizontalAlignment="Center"
@@ -42,7 +56,7 @@
Margin="10" Margin="10"
Source="{Binding IconBitmapImage}"/> Source="{Binding IconBitmapImage}"/>
<TextBlock <TextBlock
Grid.Column="1" Grid.Column="2"
Text="{Binding RepeatIndexString, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Text="{Binding RepeatIndexString, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Foreground="{DynamicResource PrimaryForegroundBrush}" Foreground="{DynamicResource PrimaryForegroundBrush}"
FontSize="14" FontSize="14"
@@ -50,7 +64,7 @@
Width="20" Width="20"
VerticalAlignment="Center"/> VerticalAlignment="Center"/>
<TextBlock <TextBlock
Grid.Column="2" Grid.Column="3"
Text="{Binding AppName}" Text="{Binding AppName}"
Foreground="{DynamicResource PrimaryForegroundBrush}" Foreground="{DynamicResource PrimaryForegroundBrush}"
FontSize="14" FontSize="14"
@@ -58,7 +72,7 @@
VerticalAlignment="Center"/> VerticalAlignment="Center"/>
<TextBox <TextBox
x:Name="CommandLineTextBox" x:Name="CommandLineTextBox"
Grid.Column="3" Grid.Column="4"
Text="{Binding CommandLineArguments, Mode=TwoWay}" Text="{Binding CommandLineArguments, Mode=TwoWay}"
Foreground="{DynamicResource PrimaryForegroundBrush}" Foreground="{DynamicResource PrimaryForegroundBrush}"
Background="{DynamicResource TertiaryBackgroundBrush}" Background="{DynamicResource TertiaryBackgroundBrush}"
@@ -67,7 +81,7 @@
FontWeight="Normal" FontWeight="Normal"
VerticalContentAlignment="Center" /> VerticalContentAlignment="Center" />
<TextBlock <TextBlock
Grid.Column="3" Grid.Column="4"
IsHitTestVisible="False" IsHitTestVisible="False"
Text="{x:Static props:Resources.WriteArgs}" Text="{x:Static props:Resources.WriteArgs}"
Foreground="{DynamicResource SecondaryForegroundBrush}" Foreground="{DynamicResource SecondaryForegroundBrush}"
@@ -88,7 +102,7 @@
</TextBlock.Style> </TextBlock.Style>
</TextBlock> </TextBlock>
<CheckBox <CheckBox
Grid.Column="4" Grid.Column="5"
IsChecked="{Binding IsSelected, Mode=TwoWay}" IsChecked="{Binding IsSelected, Mode=TwoWay}"
Checked="CheckBox_Checked" Checked="CheckBox_Checked"
Unchecked="CheckBox_Checked" Unchecked="CheckBox_Checked"

View File

@@ -285,6 +285,15 @@ namespace ProjectsEditor.Properties {
} }
} }
/// <summary>
/// Looks up a localized string similar to The application cannot be found.
/// </summary>
public static string NotFoundTooltip {
get {
return ResourceManager.GetString("NotFoundTooltip", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to an hour ago. /// Looks up a localized string similar to an hour ago.
/// </summary> /// </summary>

View File

@@ -189,6 +189,9 @@
<data name="New_project" xml:space="preserve"> <data name="New_project" xml:space="preserve">
<value>New project</value> <value>New project</value>
</data> </data>
<data name="NotFoundTooltip" xml:space="preserve">
<value>The application cannot be found</value>
</data>
<data name="No_Projects_Message" xml:space="preserve"> <data name="No_Projects_Message" xml:space="preserve">
<value>There are no saved projects.</value> <value>There are no saved projects.</value>
</data> </data>

View File

@@ -12,6 +12,7 @@ using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using ManagedCommon;
using ProjectsEditor.Models; using ProjectsEditor.Models;
namespace ProjectsEditor.Utils namespace ProjectsEditor.Utils
@@ -140,11 +141,11 @@ namespace ProjectsEditor.Utils
{ {
if (app.IsHighlighted) if (app.IsHighlighted)
{ {
graphics.DrawPath(new Pen(Common.ThemeManager.GetCurrentTheme() == Common.Theme.Dark ? Color.White : Color.DarkGray, graphics.VisibleClipBounds.Height / 25), path); graphics.DrawPath(new Pen(Common.ThemeManager.GetCurrentTheme() == Common.Theme.Dark ? Color.White : Color.DarkGray, graphics.VisibleClipBounds.Height / 50), path);
} }
else else
{ {
graphics.DrawPath(new Pen(Common.ThemeManager.GetCurrentTheme() == Common.Theme.Dark ? Color.FromArgb(128, 82, 82, 82) : Color.FromArgb(128, 160, 160, 160), graphics.VisibleClipBounds.Height / 100), path); graphics.DrawPath(new Pen(Common.ThemeManager.GetCurrentTheme() == Common.Theme.Dark ? Color.FromArgb(128, 82, 82, 82) : Color.FromArgb(128, 160, 160, 160), graphics.VisibleClipBounds.Height / 200), path);
} }
graphics.FillPath(brush, path); graphics.FillPath(brush, path);
@@ -198,11 +199,11 @@ namespace ProjectsEditor.Utils
{ {
if (apps.Where(x => x.IsHighlighted).Any()) if (apps.Where(x => x.IsHighlighted).Any())
{ {
graphics.DrawPath(new Pen(Common.ThemeManager.GetCurrentTheme() == Common.Theme.Dark ? Color.White : Color.DarkGray, graphics.VisibleClipBounds.Height / 25), path); graphics.DrawPath(new Pen(Common.ThemeManager.GetCurrentTheme() == Common.Theme.Dark ? Color.White : Color.DarkGray, graphics.VisibleClipBounds.Height / 50), path);
} }
else else
{ {
graphics.DrawPath(new Pen(Common.ThemeManager.GetCurrentTheme() == Common.Theme.Dark ? Color.FromArgb(128, 82, 82, 82) : Color.FromArgb(128, 160, 160, 160), graphics.VisibleClipBounds.Height / 100), path); graphics.DrawPath(new Pen(Common.ThemeManager.GetCurrentTheme() == Common.Theme.Dark ? Color.FromArgb(128, 82, 82, 82) : Color.FromArgb(128, 160, 160, 160), graphics.VisibleClipBounds.Height / 200), path);
} }
graphics.FillPath(brush, path); graphics.FillPath(brush, path);
@@ -395,6 +396,53 @@ namespace ProjectsEditor.Utils
return shortcutIconFilename; return shortcutIconFilename;
} }
internal static BitmapImage DrawPreviewIcons(Project project)
{
var selectedApps = project.Applications.Where(x => x.IsSelected);
int appsCount = selectedApps.Count();
if (appsCount == 0)
{
return null;
}
Bitmap previewBitmap = new Bitmap(32 * appsCount, 24);
using (Graphics graphics = Graphics.FromImage(previewBitmap))
{
graphics.SmoothingMode = SmoothingMode.AntiAlias;
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
int appIndex = 0;
foreach (var app in selectedApps)
{
try
{
graphics.DrawIcon(app.Icon, new Rectangle(32 * appIndex, 0, 24, 24));
}
catch (Exception e)
{
Logger.LogError($"Exception while drawing the icon for app {app.AppName}. Exception message: {e.Message}");
}
appIndex++;
}
}
using (var memory = new MemoryStream())
{
previewBitmap.Save(memory, ImageFormat.Png);
memory.Position = 0;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = memory;
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.EndInit();
bitmapImage.Freeze();
return bitmapImage;
}
}
private static void CreateExamples(Project project) private static void CreateExamples(Project project)
{ {
Bitmap bitmap = new Bitmap(IconSize + 1000, IconSize * iconBrushes.Count); Bitmap bitmap = new Bitmap(IconSize + 1000, IconSize * iconBrushes.Count);

View File

@@ -118,6 +118,7 @@ namespace ProjectsEditor.Utils
Maximized = app.Maximized, Maximized = app.Maximized,
Minimized = app.Minimized, Minimized = app.Minimized,
IsSelected = true, IsSelected = true,
IsNotFound = false,
Position = new Models.Application.WindowPosition() Position = new Models.Application.WindowPosition()
{ {
Height = app.Position.Height, Height = app.Position.Height,