mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-24 04:00:02 +01:00
Remove Peek.UI.WPF project
This commit is contained in:
@@ -470,8 +470,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GPOWrapperProjection", "src
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Peek", "Peek", "{17B4FA70-001E-4D33-BBBB-0D142DBC2E20}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Peek.UI.WPF", "src\modules\peek\Peek.UI.WPF\Peek.UI.WPF.csproj", "{C0240BC3-95AF-4B38-811A-76E3FD56B576}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Peek", "src\modules\peek\peek\peek.vcxproj", "{A1425B53-3D61-4679-8623-E64A0D3D0A48}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Peek.UI", "src\modules\peek\Peek.UI\Peek.UI.csproj", "{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}"
|
||||
@@ -1927,18 +1925,6 @@ Global
|
||||
{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97}.Release|x64.Build.0 = Release|x64
|
||||
{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97}.Release|x86.ActiveCfg = Release|x64
|
||||
{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97}.Release|x86.Build.0 = Release|x64
|
||||
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Debug|x64.Build.0 = Debug|x64
|
||||
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Debug|x86.Build.0 = Debug|x64
|
||||
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Release|x64.ActiveCfg = Release|x64
|
||||
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Release|x64.Build.0 = Release|x64
|
||||
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Release|x86.ActiveCfg = Release|x64
|
||||
{C0240BC3-95AF-4B38-811A-76E3FD56B576}.Release|x86.Build.0 = Release|x64
|
||||
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Debug|x64.ActiveCfg = Debug|x64
|
||||
@@ -2275,7 +2261,6 @@ Global
|
||||
{E599C30B-9DC8-4E5A-BF27-93D4CCEDE788} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97} = {1AFB6476-670D-4E80-A464-657E01DFF482}
|
||||
{17B4FA70-001E-4D33-BBBB-0D142DBC2E20} = {4574FDD0-F61D-4376-98BF-E5A1262C11EC}
|
||||
{C0240BC3-95AF-4B38-811A-76E3FD56B576} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
|
||||
{A1425B53-3D61-4679-8623-E64A0D3D0A48} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
|
||||
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<Application
|
||||
x:Class="Peek.UI.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
StartupUri="Views/MainWindow.xaml">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ui:ThemeResources />
|
||||
<ui:XamlControlsResources />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
@@ -1,94 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using Common.UI;
|
||||
using ManagedCommon;
|
||||
|
||||
namespace Peek.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application, IDisposable
|
||||
{
|
||||
private ThemeManager? _themeManager;
|
||||
|
||||
private Mutex? _instanceMutex;
|
||||
private static string[] _args = Array.Empty<string>();
|
||||
private int _powerToysRunnerPid;
|
||||
private bool disposedValue;
|
||||
|
||||
// TODO: Make sure no window appears or blinks at startup
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
_args = e?.Args ?? Array.Empty<string>();
|
||||
|
||||
// allow only one instance of peek
|
||||
_instanceMutex = new Mutex(true, @"Local\PowerToys_Peek_InstanceMutex", out bool createdNew);
|
||||
if (!createdNew)
|
||||
{
|
||||
_instanceMutex = null;
|
||||
Environment.Exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_args?.Length > 0)
|
||||
{
|
||||
_ = int.TryParse(_args[0], out _powerToysRunnerPid);
|
||||
|
||||
RunnerHelper.WaitForPowerToysRunner(_powerToysRunnerPid, () =>
|
||||
{
|
||||
Environment.Exit(0);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
_powerToysRunnerPid = -1;
|
||||
}
|
||||
|
||||
_themeManager = new ThemeManager(this);
|
||||
base.OnStartup(e);
|
||||
}
|
||||
|
||||
protected override void OnExit(ExitEventArgs e)
|
||||
{
|
||||
if (_instanceMutex != null)
|
||||
{
|
||||
_instanceMutex.ReleaseMutex();
|
||||
}
|
||||
|
||||
base.OnExit(e);
|
||||
}
|
||||
|
||||
protected virtual void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposedValue)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
_instanceMutex?.Dispose();
|
||||
}
|
||||
|
||||
// TODO: free unmanaged resources (unmanaged objects) and override finalizer
|
||||
// TODO: set large fields to null
|
||||
disposedValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public bool IsRunningDetachedFromPowerToys()
|
||||
{
|
||||
return _powerToysRunnerPid == -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Windows;
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, // where theme specific resource dictionaries are located (used if a resource is not found in the page, or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly) // where the generic resource dictionary is locate (used if a resource is not found in the page, app, or any theme specific resource dictionaries)
|
||||
]
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 KiB |
@@ -1,21 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Peek.UI.Extensions
|
||||
{
|
||||
public static class LinkedListNodeExtensions
|
||||
{
|
||||
public static LinkedListNode<T>? GetNextOrFirst<T>(this LinkedListNode<T> current)
|
||||
{
|
||||
return current.Next ?? current.List?.First;
|
||||
}
|
||||
|
||||
public static LinkedListNode<T>? GetPreviousOrLast<T>(this LinkedListNode<T> current)
|
||||
{
|
||||
return current.Previous ?? current.List?.Last;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Windows;
|
||||
|
||||
namespace Peek.UI.Extensions
|
||||
{
|
||||
public static class SizeExtensions
|
||||
{
|
||||
public static Rect Fit(this Size sizeToFit, Rect bounds, Size maxSize, Size minSize, Size allowedGap, double reservedHeight)
|
||||
{
|
||||
double resultingWidth = sizeToFit.Width;
|
||||
double resultingHeight = sizeToFit.Height;
|
||||
|
||||
var ratioWidth = sizeToFit.Width / maxSize.Width;
|
||||
var ratioHeight = sizeToFit.Height / maxSize.Height;
|
||||
|
||||
if (ratioWidth > ratioHeight)
|
||||
{
|
||||
if (ratioWidth > 1)
|
||||
{
|
||||
resultingWidth = maxSize.Width;
|
||||
resultingHeight = sizeToFit.Height / ratioWidth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ratioHeight > 1)
|
||||
{
|
||||
resultingWidth = sizeToFit.Width / ratioHeight;
|
||||
resultingHeight = maxSize.Height;
|
||||
}
|
||||
}
|
||||
|
||||
if (resultingWidth < minSize.Width - allowedGap.Width)
|
||||
{
|
||||
resultingWidth = minSize.Width;
|
||||
}
|
||||
|
||||
if (resultingHeight < minSize.Height - allowedGap.Height)
|
||||
{
|
||||
resultingHeight = minSize.Height;
|
||||
}
|
||||
|
||||
resultingHeight += reservedHeight;
|
||||
|
||||
// Calculate offsets to center content
|
||||
double offsetX = (maxSize.Width - resultingWidth) / 2;
|
||||
double offsetY = (maxSize.Height - resultingHeight) / 2;
|
||||
|
||||
var maxWindowLeft = bounds.Left + ((bounds.Right - bounds.Left - maxSize.Width) / 2);
|
||||
var maxWindowTop = bounds.Top + ((bounds.Bottom - bounds.Top - maxSize.Height) / 2);
|
||||
|
||||
var resultingLeft = maxWindowLeft + offsetX;
|
||||
var resultingTop = maxWindowTop + offsetY;
|
||||
|
||||
return new Rect(resultingLeft, resultingTop, resultingWidth, resultingHeight);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
using Peek.UI.Native;
|
||||
using static Peek.UI.Native.NativeModels;
|
||||
|
||||
namespace Peek.UI.Extensions
|
||||
{
|
||||
public static class WindowExtensions
|
||||
{
|
||||
public static void SetToolStyle(this Window window)
|
||||
{
|
||||
var handle = new WindowInteropHelper(window).Handle;
|
||||
_ = NativeMethods.SetWindowLong(handle, GwlExStyle, NativeMethods.GetWindowLong(handle, GwlExStyle) | WsExToolWindow);
|
||||
}
|
||||
|
||||
public static void BringToForeground(this Window window)
|
||||
{
|
||||
// Use SendInput hack to allow Activate to work - required to resolve focus issue https://github.com/microsoft/PowerToys/issues/4270
|
||||
Input input = new Input { Type = InputType.InputMouse, Data = { } };
|
||||
Input[] inputs = new Input[] { input };
|
||||
|
||||
// Send empty mouse event. This makes this thread the last to send input, and hence allows it to pass foreground permission checks
|
||||
_ = NativeMethods.SendInput(1, inputs, Input.Size);
|
||||
|
||||
window.Activate();
|
||||
}
|
||||
|
||||
public static void RoundCorners(this Window window)
|
||||
{
|
||||
IntPtr hWnd = new System.Windows.Interop.WindowInteropHelper(Window.GetWindow(window)).EnsureHandle();
|
||||
var attribute = DwmWindowAttributed.DwmaWindowCornerPreference;
|
||||
var preference = DwmWindowCornerPreference.DwmCpRound;
|
||||
NativeMethods.DwmSetWindowAttribute(hWnd, attribute, ref preference, sizeof(uint));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Peek.UI.Helpers
|
||||
{
|
||||
public static class FileExplorerHelper
|
||||
{
|
||||
public static IEnumerable<string> GetSelectedItems(IntPtr handle)
|
||||
{
|
||||
var selectedItems = new List<string>();
|
||||
var shell = new Shell32.Shell();
|
||||
foreach (SHDocVw.InternetExplorer window in shell.Windows())
|
||||
{
|
||||
if (window.HWND == (int)handle)
|
||||
{
|
||||
Shell32.FolderItems items = ((Shell32.IShellFolderViewDual2)window.Document).SelectedItems();
|
||||
if (items != null && items.Count > 0)
|
||||
{
|
||||
foreach (Shell32.FolderItem item in items)
|
||||
{
|
||||
selectedItems.Add(item.Path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return selectedItems;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Peek.UI.Models;
|
||||
|
||||
namespace Peek.UI.Helpers
|
||||
{
|
||||
public static class FileLoadHelper
|
||||
{
|
||||
public static Task<DimensionData> LoadDimensionsAsync(string filename)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
Size size = new Size(0, 0);
|
||||
try
|
||||
{
|
||||
using (FileStream stream = File.OpenRead(filename))
|
||||
{
|
||||
string extension = Path.GetExtension(stream.Name);
|
||||
if (FileTypeHelper.IsSupportedImage(extension))
|
||||
{
|
||||
using (System.Drawing.Image sourceImage = System.Drawing.Image.FromStream(stream, false, false))
|
||||
{
|
||||
var rotation = EvaluateRotationToApply(sourceImage);
|
||||
if (rotation == Rotation.Rotate90 || rotation == Rotation.Rotate270)
|
||||
{
|
||||
size = new Size(sourceImage.Height, sourceImage.Width);
|
||||
}
|
||||
else
|
||||
{
|
||||
size = new Size(sourceImage.Width, sourceImage.Height);
|
||||
}
|
||||
|
||||
return Task.FromResult(new DimensionData { Size = size, Rotation = rotation });
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return Task.FromResult(new DimensionData { Size = size, Rotation = Rotation.Rotate0 });
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return Task.FromResult(new DimensionData { Size = size, Rotation = Rotation.Rotate0 });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static async Task<BitmapSource> LoadThumbnailAsync(string filename, bool iconFallback)
|
||||
{
|
||||
var thumbnail = await Task.Run(() =>
|
||||
{
|
||||
var bitmapSource = ThumbnailHelper.GetThumbnail(filename, iconFallback);
|
||||
bitmapSource.Freeze();
|
||||
return bitmapSource;
|
||||
});
|
||||
|
||||
return thumbnail;
|
||||
}
|
||||
|
||||
public static Task<BitmapSource> LoadIconAsync(string filename)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var bitmapSource = ThumbnailHelper.GetIcon(filename);
|
||||
bitmapSource.Freeze();
|
||||
return bitmapSource;
|
||||
});
|
||||
}
|
||||
|
||||
public static Task<BitmapImage> LoadFullImageAsync(string filename, Rotation rotation)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
var bitmap = new BitmapImage();
|
||||
bitmap.BeginInit();
|
||||
bitmap.CacheOption = BitmapCacheOption.OnLoad;
|
||||
bitmap.UriSource = new Uri(filename);
|
||||
bitmap.Rotation = rotation;
|
||||
bitmap.EndInit();
|
||||
bitmap.Freeze();
|
||||
return bitmap;
|
||||
});
|
||||
}
|
||||
|
||||
private static Rotation EvaluateRotationToApply(System.Drawing.Image image)
|
||||
{
|
||||
PropertyItem? property = image.PropertyItems?.FirstOrDefault(p => p.Id == 274);
|
||||
|
||||
if (property != null && property.Value != null && property.Value.Length > 0)
|
||||
{
|
||||
int orientation = property.Value[0];
|
||||
|
||||
if (orientation == 6)
|
||||
{
|
||||
return Rotation.Rotate90;
|
||||
}
|
||||
|
||||
if (orientation == 3)
|
||||
{
|
||||
return Rotation.Rotate180;
|
||||
}
|
||||
|
||||
if (orientation == 8)
|
||||
{
|
||||
return Rotation.Rotate270;
|
||||
}
|
||||
}
|
||||
|
||||
return Rotation.Rotate0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Peek.UI.Native;
|
||||
using static Peek.UI.Native.NativeModels;
|
||||
|
||||
namespace Peek.UI.Helpers
|
||||
{
|
||||
public static class FileTypeHelper
|
||||
{
|
||||
public static bool IsSupportedImage(string extension) => extension switch
|
||||
{
|
||||
".bmp" => true,
|
||||
".gif" => true,
|
||||
".jpg" => true,
|
||||
".jfif" => true,
|
||||
".jfi" => true,
|
||||
".jif" => true,
|
||||
".jpeg" => true,
|
||||
".jpe" => true,
|
||||
".png" => true,
|
||||
".tif" => true,
|
||||
".tiff" => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
public static bool IsMedia(string extension)
|
||||
{
|
||||
return IsImage(extension) || IsVideo(extension);
|
||||
}
|
||||
|
||||
public static bool IsImage(string extension)
|
||||
{
|
||||
return IsPerceivedType(extension, PerceivedType.Image);
|
||||
}
|
||||
|
||||
public static bool IsVideo(string extension)
|
||||
{
|
||||
return IsPerceivedType(extension, PerceivedType.Video);
|
||||
}
|
||||
|
||||
public static bool IsDocument(string extension)
|
||||
{
|
||||
return IsPerceivedType(extension, PerceivedType.Document);
|
||||
}
|
||||
|
||||
internal static bool IsPerceivedType(string extension, PerceivedType perceivedType)
|
||||
{
|
||||
if (string.IsNullOrEmpty(extension))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PerceivedType perceived;
|
||||
Perceived flag;
|
||||
bool isPerceivedType = false;
|
||||
|
||||
try
|
||||
{
|
||||
if (NativeMethods.AssocGetPerceivedType(extension, out perceived, out flag, IntPtr.Zero) == HResult.Ok)
|
||||
{
|
||||
isPerceivedType = perceived == perceivedType;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// TODO: AssocGetPerceivedType throws on some file types (json, ps1, exe, etc.)
|
||||
// Properly handle these
|
||||
return false;
|
||||
}
|
||||
|
||||
return isPerceivedType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,128 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Peek.UI.Models;
|
||||
using Peek.UI.Native;
|
||||
using static Peek.UI.Native.NativeModels;
|
||||
|
||||
namespace Peek.UI.Helpers
|
||||
{
|
||||
public static class ThumbnailHelper
|
||||
{
|
||||
private static readonly Assembly Assembly = Assembly.GetExecutingAssembly();
|
||||
public static readonly string ProgramDirectory = Directory.GetParent(Assembly.Location)!.ToString();
|
||||
public static readonly string ErrorIcon = Path.Combine(ProgramDirectory, "Assets", "error.png");
|
||||
|
||||
// Based on https://stackoverflow.com/questions/21751747/extract-thumbnail-for-any-file-in-windows
|
||||
private const string IShellItem2Guid = "7E9FB0D3-919F-4307-AB2E-9B1860310C93";
|
||||
|
||||
public static BitmapSource GetIcon(string fileName)
|
||||
{
|
||||
IntPtr hbitmap;
|
||||
HResult hr = GetIconImpl(Path.GetFullPath(fileName), out hbitmap);
|
||||
|
||||
if (hr != HResult.Ok)
|
||||
{
|
||||
return new BitmapImage(new Uri(ErrorIcon));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
|
||||
}
|
||||
finally
|
||||
{
|
||||
// delete HBitmap to avoid memory leaks
|
||||
NativeMethods.DeleteObject(hbitmap);
|
||||
}
|
||||
}
|
||||
|
||||
public static BitmapSource GetThumbnail(string fileName, bool iconFallback)
|
||||
{
|
||||
IntPtr hbitmap;
|
||||
HResult hr = GetThumbnailImpl(Path.GetFullPath(fileName), out hbitmap);
|
||||
|
||||
if (hr != HResult.Ok && iconFallback)
|
||||
{
|
||||
return GetIcon(fileName);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
|
||||
}
|
||||
finally
|
||||
{
|
||||
// delete HBitmap to avoid memory leaks
|
||||
NativeMethods.DeleteObject(hbitmap);
|
||||
}
|
||||
}
|
||||
|
||||
private static HResult GetIconImpl(string filename, out IntPtr hbitmap)
|
||||
{
|
||||
Guid shellItem2Guid = new Guid(IShellItem2Guid);
|
||||
int retCode = NativeMethods.SHCreateItemFromParsingName(filename, IntPtr.Zero, ref shellItem2Guid, out IShellItem nativeShellItem);
|
||||
|
||||
if (retCode != 0)
|
||||
{
|
||||
throw Marshal.GetExceptionForHR(retCode)!;
|
||||
}
|
||||
|
||||
NativeSize large = new NativeSize { Width = 256, Height = 256 };
|
||||
var options = ThumbnailOptions.BiggerSizeOk | ThumbnailOptions.IconOnly;
|
||||
|
||||
HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(large, options, out hbitmap);
|
||||
|
||||
Marshal.ReleaseComObject(nativeShellItem);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
private static HResult GetThumbnailImpl(string filename, out IntPtr hbitmap)
|
||||
{
|
||||
Guid shellItem2Guid = new Guid(IShellItem2Guid);
|
||||
int retCode = NativeMethods.SHCreateItemFromParsingName(filename, IntPtr.Zero, ref shellItem2Guid, out IShellItem nativeShellItem);
|
||||
|
||||
if (retCode != 0)
|
||||
{
|
||||
throw Marshal.GetExceptionForHR(retCode)!;
|
||||
}
|
||||
|
||||
var extraLarge = new NativeSize { Width = 1024, Height = 1024, };
|
||||
var large = new NativeSize { Width = 256, Height = 256 };
|
||||
var medium = new NativeSize { Width = 96, Height = 96 };
|
||||
var small = new NativeSize { Width = 32, Height = 32 };
|
||||
|
||||
var options = ThumbnailOptions.BiggerSizeOk | ThumbnailOptions.ThumbnailOnly | ThumbnailOptions.ScaleUp;
|
||||
|
||||
HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(extraLarge, options, out hbitmap);
|
||||
|
||||
if (hr != HResult.Ok)
|
||||
{
|
||||
hr = ((IShellItemImageFactory)nativeShellItem).GetImage(large, options, out hbitmap);
|
||||
}
|
||||
|
||||
if (hr != HResult.Ok)
|
||||
{
|
||||
hr = ((IShellItemImageFactory)nativeShellItem).GetImage(medium, options, out hbitmap);
|
||||
}
|
||||
|
||||
if (hr != HResult.Ok)
|
||||
{
|
||||
hr = ((IShellItemImageFactory)nativeShellItem).GetImage(small, options, out hbitmap);
|
||||
}
|
||||
|
||||
Marshal.ReleaseComObject(nativeShellItem);
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Peek.UI.Models
|
||||
{
|
||||
public class DimensionData
|
||||
{
|
||||
public Size Size { get; set; }
|
||||
|
||||
public Rotation Rotation { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using static Peek.UI.Native.NativeModels;
|
||||
|
||||
namespace Peek.UI.Models
|
||||
{
|
||||
[ComImport]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
|
||||
internal interface IShellItem
|
||||
{
|
||||
void BindToHandler(
|
||||
IntPtr pbc,
|
||||
[MarshalAs(UnmanagedType.LPStruct)] Guid bhid,
|
||||
[MarshalAs(UnmanagedType.LPStruct)] Guid riid,
|
||||
out IntPtr ppv);
|
||||
|
||||
void GetParent(out IShellItem ppsi);
|
||||
|
||||
void GetDisplayName(Sigdn sigdnName, out IntPtr ppszName);
|
||||
|
||||
void GetAttributes(uint sfgaoMask, out uint psfgaoAttribs);
|
||||
|
||||
void Compare(IShellItem psi, uint hint, out int piOrder);
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Peek.UI.Models
|
||||
{
|
||||
public abstract class ObservableObject : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
protected virtual void OnPropertyChanged([CallerMemberName] string? propertyName = null)
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Peek.UI.Models
|
||||
{
|
||||
public class ObservableRectangle : ObservableObject
|
||||
{
|
||||
private double _left;
|
||||
|
||||
public double Left
|
||||
{
|
||||
get
|
||||
{
|
||||
return _left;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_left != value)
|
||||
{
|
||||
_left = value;
|
||||
OnPropertyChanged(nameof(Left));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private double _top;
|
||||
|
||||
public double Top
|
||||
{
|
||||
get
|
||||
{
|
||||
return _top;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_top != value)
|
||||
{
|
||||
_top = value;
|
||||
OnPropertyChanged(nameof(Top));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private double _height;
|
||||
|
||||
public double Height
|
||||
{
|
||||
get
|
||||
{
|
||||
return _height;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_height != value)
|
||||
{
|
||||
_height = value;
|
||||
OnPropertyChanged(nameof(Height));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private double _width;
|
||||
|
||||
public double Width
|
||||
{
|
||||
get
|
||||
{
|
||||
return _width;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_width != value)
|
||||
{
|
||||
_width = value;
|
||||
OnPropertyChanged(nameof(Width));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Windows;
|
||||
|
||||
namespace Peek.UI.Models
|
||||
{
|
||||
public class ObservableWindowData : ObservableObject
|
||||
{
|
||||
private double _titleBarHeight;
|
||||
|
||||
public double TitleBarHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
return _titleBarHeight;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_titleBarHeight != value)
|
||||
{
|
||||
_titleBarHeight = value;
|
||||
OnPropertyChanged(nameof(TitleBarHeight));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ObservableRectangle _rectangle = new ObservableRectangle();
|
||||
|
||||
public ObservableRectangle Rectangle
|
||||
{
|
||||
get
|
||||
{
|
||||
return _rectangle;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_rectangle != value)
|
||||
{
|
||||
_rectangle = value;
|
||||
OnPropertyChanged(nameof(Rectangle));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _title = string.Empty;
|
||||
|
||||
public string Title
|
||||
{
|
||||
get
|
||||
{
|
||||
return _title;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_title != value)
|
||||
{
|
||||
_title = value;
|
||||
OnPropertyChanged(nameof(Title));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Visibility _visibility;
|
||||
|
||||
public Visibility Visibility
|
||||
{
|
||||
get
|
||||
{
|
||||
return _visibility;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_visibility != value)
|
||||
{
|
||||
_visibility = value;
|
||||
|
||||
OnPropertyChanged(nameof(Visibility));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
|
||||
namespace Peek.UI.Native
|
||||
{
|
||||
public static class NativeEventWaiter
|
||||
{
|
||||
public static void WaitForEventLoop(string eventName, Action callback)
|
||||
{
|
||||
new Thread(() =>
|
||||
{
|
||||
var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName);
|
||||
while (true)
|
||||
{
|
||||
if (eventHandle.WaitOne())
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(callback);
|
||||
}
|
||||
}
|
||||
}).Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Peek.UI.Models;
|
||||
using static Peek.UI.Native.NativeModels;
|
||||
|
||||
namespace Peek.UI.Native
|
||||
{
|
||||
public static class NativeMethods
|
||||
{
|
||||
[DllImport("dwmapi.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern long DwmSetWindowAttribute(
|
||||
IntPtr hwnd,
|
||||
DwmWindowAttributed attribute,
|
||||
ref DwmWindowCornerPreference pvAttribute,
|
||||
uint cbAttribute);
|
||||
|
||||
[DllImport("gdi32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool DeleteObject(IntPtr hObject);
|
||||
|
||||
[DllImport("Shlwapi.dll", ExactSpelling = true, PreserveSig = false)]
|
||||
internal static extern HResult AssocGetPerceivedType(
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string extension,
|
||||
out PerceivedType perceivedType,
|
||||
out Perceived perceivedFlags,
|
||||
IntPtr ptrType);
|
||||
|
||||
[DllImport("shell32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern int SHCreateItemFromParsingName(
|
||||
[MarshalAs(UnmanagedType.LPWStr)] string path,
|
||||
IntPtr pbc,
|
||||
ref Guid riid,
|
||||
[MarshalAs(UnmanagedType.Interface)] out IShellItem shellItem);
|
||||
|
||||
[DllImport("user32.dll", SetLastError = true)]
|
||||
internal static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
|
||||
internal static extern IntPtr GetForegroundWindow();
|
||||
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
|
||||
internal static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
internal static extern uint SendInput(uint nInputs, Input[] pInputs, int cbSize);
|
||||
}
|
||||
}
|
||||
@@ -1,182 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Peek.UI.Native
|
||||
{
|
||||
public class NativeModels
|
||||
{
|
||||
public const int GwlExStyle = -20;
|
||||
public const int WsExToolWindow = 0x00000080;
|
||||
|
||||
public enum PerceivedType
|
||||
{
|
||||
Folder = -1,
|
||||
Unknown = 0,
|
||||
Image = 2,
|
||||
Video = 4,
|
||||
Document = 6,
|
||||
}
|
||||
|
||||
public enum Perceived
|
||||
{
|
||||
Undefined = 0x0000,
|
||||
Softcoded = 0x0001,
|
||||
Hardcoded = 0x0002,
|
||||
NativeSupport = 0x0004,
|
||||
GdiPlus = 0x0010,
|
||||
WMSDK = 0x0020,
|
||||
ZipFolder = 0x0040,
|
||||
}
|
||||
|
||||
public enum HResult
|
||||
{
|
||||
Ok = 0x0000,
|
||||
False = 0x0001,
|
||||
InvalidArguments = unchecked((int)0x80070057),
|
||||
OutOfMemory = unchecked((int)0x8007000E),
|
||||
NoInterface = unchecked((int)0x80004002),
|
||||
Fail = unchecked((int)0x80004005),
|
||||
ExtractionFailed = unchecked((int)0x8004B200),
|
||||
ElementNotFound = unchecked((int)0x80070490),
|
||||
TypeElementNotFound = unchecked((int)0x8002802B),
|
||||
NoObject = unchecked((int)0x800401E5),
|
||||
Win32ErrorCanceled = 1223,
|
||||
Canceled = unchecked((int)0x800704C7),
|
||||
ResourceInUse = unchecked((int)0x800700AA),
|
||||
AccessDenied = unchecked((int)0x80030005),
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct Input
|
||||
{
|
||||
public InputType Type;
|
||||
public InputUnion Data;
|
||||
|
||||
public static int Size
|
||||
{
|
||||
get { return Marshal.SizeOf(typeof(Input)); }
|
||||
}
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public struct InputUnion
|
||||
{
|
||||
[FieldOffset(0)]
|
||||
public MouseInput Mi;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public KeybdInput Ki;
|
||||
|
||||
[FieldOffset(0)]
|
||||
public HardwareInput Hi;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct MouseInput
|
||||
{
|
||||
public int Dx;
|
||||
public int Dy;
|
||||
public int MouseData;
|
||||
public uint DwFlags;
|
||||
public uint Time;
|
||||
public UIntPtr DwExtraInfo;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct KeybdInput
|
||||
{
|
||||
public short WVk;
|
||||
public short WScan;
|
||||
public uint DwFlags;
|
||||
public int Time;
|
||||
public UIntPtr DwExtraInfo;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct HardwareInput
|
||||
{
|
||||
public int UMsg;
|
||||
public short WParamL;
|
||||
public short WParamH;
|
||||
}
|
||||
|
||||
public enum InputType : uint
|
||||
{
|
||||
InputMouse = 0,
|
||||
InputKeyboard = 1,
|
||||
InputHardware = 2,
|
||||
}
|
||||
|
||||
public enum Sigdn : uint
|
||||
{
|
||||
NormalDisplay = 0,
|
||||
ParentRelativeParsing = 0x80018001,
|
||||
ParentRelativeForAddressBar = 0x8001c001,
|
||||
DesktopAbsoluteParsing = 0x80028000,
|
||||
ParentRelativeEditing = 0x80031001,
|
||||
DesktopAbsoluteEditing = 0x8004c000,
|
||||
FileSysPath = 0x80058000,
|
||||
Url = 0x80068000,
|
||||
}
|
||||
|
||||
public enum DwmWindowAttributed
|
||||
{
|
||||
DwmaWindowCornerPreference = 33,
|
||||
}
|
||||
|
||||
// The DWM_WINDOW_CORNER_PREFERENCE enum for DwmSetWindowAttribute's third parameter, which tells the function
|
||||
// what value of the enum to set.
|
||||
public enum DwmWindowCornerPreference
|
||||
{
|
||||
DwmCpDefault = 0,
|
||||
DwmCpDoNotRound = 1,
|
||||
DwmCpRound = 2,
|
||||
DwmCpRoundSmall = 3,
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ThumbnailOptions
|
||||
{
|
||||
None = 0x00,
|
||||
BiggerSizeOk = 0x01,
|
||||
InMemoryOnly = 0x02,
|
||||
IconOnly = 0x04,
|
||||
ThumbnailOnly = 0x08,
|
||||
InCacheOnly = 0x10,
|
||||
ScaleUp = 0x100,
|
||||
}
|
||||
|
||||
[ComImport]
|
||||
[Guid("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
internal interface IShellItemImageFactory
|
||||
{
|
||||
[PreserveSig]
|
||||
HResult GetImage(
|
||||
[In, MarshalAs(UnmanagedType.Struct)] NativeSize size,
|
||||
[In] ThumbnailOptions flags,
|
||||
[Out] out IntPtr phbm);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
internal struct NativeSize
|
||||
{
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
public int Width
|
||||
{
|
||||
set { width = value; }
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
set { height = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
|
||||
<AssemblyName>PowerToys.Peek.UI.WPF</AssemblyName>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\modules\Peek.WPF\</OutputPath>
|
||||
<UseWindowsForms>True</UseWindowsForms>
|
||||
<ApplicationIcon>Resources\FluentIconsPeek.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<COMReference Include="Shell32">
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<Guid>50a7e9b0-70ef-11d1-b75a-00a0c90564fe</Guid>
|
||||
<Lcid>0</Lcid>
|
||||
<Isolated>false</Isolated>
|
||||
<EmbedInteropTypes>true</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
<COMReference Include="SHDocVw">
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<VersionMinor>1</VersionMinor>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<Guid>eab22ac0-30c1-11cf-a7eb-0000c05bae0b</Guid>
|
||||
<Lcid>0</Lcid>
|
||||
<Isolated>false</Isolated>
|
||||
<EmbedInteropTypes>true</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>Resources\Peek.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\Peek.ico" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="Resources\Peek.ico">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
<None Update="Assets\error.png">
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ModernWpfUI" Version="0.9.4" />
|
||||
<PackageReference Include="WpfScreenHelper" Version="2.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\Common.UI\Common.UI.csproj" />
|
||||
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" />
|
||||
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="Themes\Dark.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="Themes\HighContrast1.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="Themes\HighContrast2.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="Themes\HighContrastBlack.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="Themes\HighContrastWhite.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
<Page Update="Themes\Light.xaml">
|
||||
<XamlRuntime>$(DefaultXamlRuntime)</XamlRuntime>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Views\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 149 KiB |
@@ -1,19 +0,0 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=System.Runtime">
|
||||
|
||||
<!-- Metadata -->
|
||||
<system:String x:Key="Theme.Name">Dark.Accent1</system:String>
|
||||
<system:String x:Key="Theme.Origin">PowerToysPeek</system:String>
|
||||
<system:String x:Key="Theme.DisplayName">Accent1 (Dark)</system:String>
|
||||
<system:String x:Key="Theme.BaseColorScheme">Dark</system:String>
|
||||
<system:String x:Key="Theme.ColorScheme">Accent1</system:String>
|
||||
<Color x:Key="Theme.PrimaryAccentColor">Black</Color>
|
||||
|
||||
<SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="#FF3a3a3a" />
|
||||
<SolidColorBrush x:Key="PrimaryBackgroundBrush" Color="#FF333333" />
|
||||
<SolidColorBrush x:Key="PrimaryForegroundBrush" Color="#FFFFFFFF" />
|
||||
<SolidColorBrush x:Key="SecondaryForegroundBrush" Color="#FF999999" />
|
||||
<SolidColorBrush x:Key="PrimaryBorderBrush" Color="Transparent" />
|
||||
</ResourceDictionary>
|
||||
@@ -1,19 +0,0 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=System.Runtime">
|
||||
|
||||
<!-- Metadata -->
|
||||
<system:String x:Key="Theme.Name">HighContrast.Accent2</system:String>
|
||||
<system:String x:Key="Theme.Origin">PowerToysPeek</system:String>
|
||||
<system:String x:Key="Theme.DisplayName">Accent2 (HighContrast)</system:String>
|
||||
<system:String x:Key="Theme.BaseColorScheme">HighContrast</system:String>
|
||||
<system:String x:Key="Theme.ColorScheme">Accent2</system:String>
|
||||
<Color x:Key="Theme.PrimaryAccentColor">White</Color>
|
||||
|
||||
<SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="#FF3a3a3a" />
|
||||
<SolidColorBrush x:Key="PrimaryBackgroundBrush" Color="#FF333333" />
|
||||
<SolidColorBrush x:Key="PrimaryForegroundBrush" Color="#FFffff00" />
|
||||
<SolidColorBrush x:Key="SecondaryForegroundBrush" Color="#FF00ff00" />
|
||||
<SolidColorBrush x:Key="PrimaryBorderBrush" Color="#FFffff00" />
|
||||
</ResourceDictionary>
|
||||
@@ -1,19 +0,0 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=System.Runtime">
|
||||
|
||||
<!-- Metadata -->
|
||||
<system:String x:Key="Theme.Name">HighContrast.Accent3</system:String>
|
||||
<system:String x:Key="Theme.Origin">PowerToysPeek</system:String>
|
||||
<system:String x:Key="Theme.DisplayName">Accent3 (HighContrast)</system:String>
|
||||
<system:String x:Key="Theme.BaseColorScheme">HighContrast</system:String>
|
||||
<system:String x:Key="Theme.ColorScheme">Accent3</system:String>
|
||||
<Color x:Key="Theme.PrimaryAccentColor">White</Color>
|
||||
|
||||
<SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="#FF3a3a3a" />
|
||||
<SolidColorBrush x:Key="PrimaryBackgroundBrush" Color="#FF333333" />
|
||||
<SolidColorBrush x:Key="PrimaryForegroundBrush" Color="#FF00ff00" />
|
||||
<SolidColorBrush x:Key="SecondaryForegroundBrush" Color="#FFc0c0c0" />
|
||||
<SolidColorBrush x:Key="PrimaryBorderBrush" Color="#FF00ff00" />
|
||||
</ResourceDictionary>
|
||||
@@ -1,19 +0,0 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=System.Runtime">
|
||||
|
||||
<!-- Metadata -->
|
||||
<system:String x:Key="Theme.Name">HighContrast.Accent4</system:String>
|
||||
<system:String x:Key="Theme.Origin">PowerToysPeek</system:String>
|
||||
<system:String x:Key="Theme.DisplayName">Accent4 (HighContrast)</system:String>
|
||||
<system:String x:Key="Theme.BaseColorScheme">HighContrast</system:String>
|
||||
<system:String x:Key="Theme.ColorScheme">Accent4</system:String>
|
||||
<Color x:Key="Theme.PrimaryAccentColor">White</Color>
|
||||
|
||||
<SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="#FF3a3a3a" />
|
||||
<SolidColorBrush x:Key="PrimaryBackgroundBrush" Color="#FF333333" />
|
||||
<SolidColorBrush x:Key="PrimaryForegroundBrush" Color="#FFffffff" />
|
||||
<SolidColorBrush x:Key="SecondaryForegroundBrush" Color="#FF1aebff" />
|
||||
<SolidColorBrush x:Key="PrimaryBorderBrush" Color="White" />
|
||||
</ResourceDictionary>
|
||||
@@ -1,19 +0,0 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=System.Runtime">
|
||||
|
||||
<!-- Metadata -->
|
||||
<system:String x:Key="Theme.Name">HighContrast.Accent5</system:String>
|
||||
<system:String x:Key="Theme.Origin">PowerToysPeek</system:String>
|
||||
<system:String x:Key="Theme.DisplayName">Accent5 (HighContrast)</system:String>
|
||||
<system:String x:Key="Theme.BaseColorScheme">HighContrast</system:String>
|
||||
<system:String x:Key="Theme.ColorScheme">Accent5</system:String>
|
||||
<Color x:Key="Theme.PrimaryAccentColor">White</Color>
|
||||
|
||||
<SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="#FFf3f3f3" />
|
||||
<SolidColorBrush x:Key="PrimaryBackgroundBrush" Color="#FFffffff" />
|
||||
<SolidColorBrush x:Key="PrimaryForegroundBrush" Color="#FF000000" />
|
||||
<SolidColorBrush x:Key="SecondaryForegroundBrush" Color="#FF676666" />
|
||||
<SolidColorBrush x:Key="PrimaryBorderBrush" Color="Black" />
|
||||
</ResourceDictionary>
|
||||
@@ -1,19 +0,0 @@
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:system="clr-namespace:System;assembly=System.Runtime">
|
||||
|
||||
<!-- Metadata -->
|
||||
<system:String x:Key="Theme.Name">Light.Accent1</system:String>
|
||||
<system:String x:Key="Theme.Origin">PowerToysPeek</system:String>
|
||||
<system:String x:Key="Theme.DisplayName">Accent1 (Light)</system:String>
|
||||
<system:String x:Key="Theme.BaseColorScheme">Light</system:String>
|
||||
<system:String x:Key="Theme.ColorScheme">Accent1</system:String>
|
||||
<Color x:Key="Theme.PrimaryAccentColor">White</Color>
|
||||
|
||||
<SolidColorBrush x:Key="SecondaryBackgroundBrush" Color="#FFf3f3f3" />
|
||||
<SolidColorBrush x:Key="PrimaryBackgroundBrush" Color="#FFffffff" />
|
||||
<SolidColorBrush x:Key="PrimaryForegroundBrush" Color="#FF000000" />
|
||||
<SolidColorBrush x:Key="SecondaryForegroundBrush" Color="#FF676666" />
|
||||
<SolidColorBrush x:Key="PrimaryBorderBrush" Color="Transparent" />
|
||||
</ResourceDictionary>
|
||||
@@ -1,301 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Peek.UI.Extensions;
|
||||
using Peek.UI.Helpers;
|
||||
using Peek.UI.Models;
|
||||
using Peek.UI.Native;
|
||||
using WpfScreenHelper;
|
||||
using Size = System.Windows.Size;
|
||||
|
||||
namespace Peek.UI.ViewModels
|
||||
{
|
||||
public class MainViewModel : ObservableObject, IDisposable
|
||||
{
|
||||
private const double ImageScale = 0.75;
|
||||
private static readonly Size MinWindowSize = new Size(720, 720);
|
||||
private static readonly Size AllowedContentGap = new Size(220, 220);
|
||||
|
||||
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
private CancellationToken CancellationToken => _cancellationTokenSource.Token;
|
||||
|
||||
public IntPtr ForegroundWindowHandle { get; internal set; }
|
||||
|
||||
public Image ImageControl { get; set; }
|
||||
|
||||
public LinkedList<string> SelectedFilePaths { get; set; } = new LinkedList<string>();
|
||||
|
||||
private BitmapSource? _bitmap;
|
||||
|
||||
public BitmapSource? Bitmap
|
||||
{
|
||||
get
|
||||
{
|
||||
return _bitmap;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_bitmap != value)
|
||||
{
|
||||
_bitmap = value;
|
||||
OnPropertyChanged(nameof(Bitmap));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private LinkedListNode<string>? _currentSelectedFilePath;
|
||||
|
||||
public LinkedListNode<string>? CurrentSelectedFilePath
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentSelectedFilePath;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_currentSelectedFilePath != value)
|
||||
{
|
||||
_currentSelectedFilePath = value;
|
||||
var title = Path.GetFileName(_currentSelectedFilePath?.Value ?? string.Empty);
|
||||
MainWindowData.Title = title;
|
||||
OnPropertyChanged(nameof(CurrentSelectedFilePath));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Visibility IsImageReady => IsLoading ? Visibility.Collapsed : Visibility.Visible;
|
||||
|
||||
private bool _isLoading = true;
|
||||
|
||||
public bool IsLoading
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isLoading;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_isLoading != value)
|
||||
{
|
||||
_isLoading = value;
|
||||
OnPropertyChanged(nameof(IsLoading));
|
||||
OnPropertyChanged(nameof(IsImageReady));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ObservableWindowData _mainWindowData = new ObservableWindowData();
|
||||
|
||||
public ObservableWindowData MainWindowData
|
||||
{
|
||||
get
|
||||
{
|
||||
return _mainWindowData;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_mainWindowData != value)
|
||||
{
|
||||
_mainWindowData = value;
|
||||
OnPropertyChanged(nameof(MainWindowData));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MainViewModel(Image imageControl)
|
||||
{
|
||||
ImageControl = imageControl;
|
||||
}
|
||||
|
||||
// TODO: Implement proper disposal pattern
|
||||
public void Dispose()
|
||||
{
|
||||
_cancellationTokenSource.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public void ClearSelection()
|
||||
{
|
||||
_cancellationTokenSource.Cancel();
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
CurrentSelectedFilePath = null;
|
||||
MainWindowData.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public bool TryUpdateSelectedFilePaths()
|
||||
{
|
||||
ForegroundWindowHandle = NativeMethods.GetForegroundWindow();
|
||||
|
||||
// TODO: Get all neighborings files in correct sorted order
|
||||
var selectedItems = FileExplorerHelper.GetSelectedItems(ForegroundWindowHandle);
|
||||
|
||||
var isDifferentSelectedItems = !SelectedFilePaths.SequenceEqual(selectedItems);
|
||||
|
||||
if (isDifferentSelectedItems)
|
||||
{
|
||||
SelectedFilePaths = new LinkedList<string>(selectedItems);
|
||||
}
|
||||
|
||||
CurrentSelectedFilePath = SelectedFilePaths.First;
|
||||
|
||||
return isDifferentSelectedItems;
|
||||
}
|
||||
|
||||
// TODO: Implement proper cancellation pattern to support quick navigation
|
||||
public async Task RenderImageToWindowAsync(string filename)
|
||||
{
|
||||
IsLoading = true;
|
||||
|
||||
var screen = Screen.FromHandle(ForegroundWindowHandle);
|
||||
Size maxWindowSize = new Size(screen.WpfBounds.Width * ImageScale, screen.WpfBounds.Height * ImageScale);
|
||||
|
||||
// TODO: Support preview or thumbnail for document files
|
||||
if (FileTypeHelper.IsSupportedImage(Path.GetExtension(filename)))
|
||||
{
|
||||
await RenderSupportedImageToWindowAsync(filename, screen.Bounds, maxWindowSize);
|
||||
}
|
||||
else if (FileTypeHelper.IsMedia(Path.GetExtension(filename)) || FileTypeHelper.IsDocument(Path.GetExtension(filename)))
|
||||
{
|
||||
await RenderMediaOrDocumentToWindowAsync(filename, screen.Bounds, maxWindowSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
await RenderUnsupportedFileToWindowAsync(filename, screen.Bounds, maxWindowSize);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RenderSupportedImageToWindowAsync(string filename, Rect windowBounds, Size maxWindowSize)
|
||||
{
|
||||
DimensionData dimensionData = await FileLoadHelper.LoadDimensionsAsync(filename);
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
return;
|
||||
}
|
||||
|
||||
var windowRect = dimensionData.Size.Fit(windowBounds, maxWindowSize, MinWindowSize, AllowedContentGap, MainWindowData.TitleBarHeight);
|
||||
|
||||
MainWindowData.Rectangle.Width = windowRect.Width;
|
||||
MainWindowData.Rectangle.Height = windowRect.Height;
|
||||
MainWindowData.Rectangle.Left = windowRect.Left;
|
||||
MainWindowData.Rectangle.Top = windowRect.Top;
|
||||
|
||||
if (dimensionData.Size.Width > MainWindowData.Rectangle.Width || dimensionData.Size.Height > MainWindowData.Rectangle.Height)
|
||||
{
|
||||
ImageControl.StretchDirection = StretchDirection.Both;
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageControl.StretchDirection = StretchDirection.DownOnly;
|
||||
}
|
||||
|
||||
await LoadImageAsync(filename, ImageControl, dimensionData.Rotation, CancellationToken);
|
||||
}
|
||||
|
||||
private async Task RenderMediaOrDocumentToWindowAsync(string filename, Rect windowBounds, Size maxWindowSize)
|
||||
{
|
||||
var bitmap = await FileLoadHelper.LoadThumbnailAsync(filename, true);
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
return;
|
||||
}
|
||||
|
||||
Bitmap = bitmap;
|
||||
|
||||
var imageSize = new Size(bitmap.PixelWidth, bitmap.PixelHeight);
|
||||
var windowRect = imageSize.Fit(windowBounds, maxWindowSize, MinWindowSize, AllowedContentGap, MainWindowData.TitleBarHeight);
|
||||
|
||||
MainWindowData.Rectangle.Width = windowRect.Width;
|
||||
MainWindowData.Rectangle.Height = windowRect.Height;
|
||||
MainWindowData.Rectangle.Left = windowRect.Left;
|
||||
MainWindowData.Rectangle.Top = windowRect.Top;
|
||||
|
||||
MainWindowData.Visibility = Visibility.Visible;
|
||||
IsLoading = false;
|
||||
}
|
||||
|
||||
private async Task RenderUnsupportedFileToWindowAsync(string filename, Rect windowBounds, Size maxWindowSize)
|
||||
{
|
||||
var contentSize = new Size(0, 0);
|
||||
var windowRect = contentSize.Fit(windowBounds, maxWindowSize, MinWindowSize, AllowedContentGap, MainWindowData.TitleBarHeight);
|
||||
|
||||
MainWindowData.Rectangle.Width = windowRect.Width;
|
||||
MainWindowData.Rectangle.Height = windowRect.Height;
|
||||
MainWindowData.Rectangle.Left = windowRect.Left;
|
||||
MainWindowData.Rectangle.Top = windowRect.Top;
|
||||
|
||||
var bitmap = await FileLoadHelper.LoadIconAsync(filename);
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
return;
|
||||
}
|
||||
|
||||
Bitmap = bitmap;
|
||||
MainWindowData.Visibility = Visibility.Visible;
|
||||
IsLoading = false;
|
||||
}
|
||||
|
||||
private Task LoadImageAsync(string filename, System.Windows.Controls.Image imageControl, Rotation rotation, CancellationToken cancellationToken)
|
||||
{
|
||||
bool isFullImageLoaded = false;
|
||||
bool isThumbnailLoaded = false;
|
||||
var thumbnailLoadTask = imageControl.Dispatcher.Invoke(async () =>
|
||||
{
|
||||
var bitmap = await FileLoadHelper.LoadThumbnailAsync(filename, false);
|
||||
isThumbnailLoaded = true;
|
||||
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isFullImageLoaded)
|
||||
{
|
||||
Bitmap = bitmap;
|
||||
MainWindowData.Visibility = Visibility.Visible;
|
||||
IsLoading = false;
|
||||
}
|
||||
});
|
||||
|
||||
var fullImageLoadTask = imageControl.Dispatcher.Invoke(async () =>
|
||||
{
|
||||
var bitmap = await FileLoadHelper.LoadFullImageAsync(filename, rotation);
|
||||
isFullImageLoaded = true;
|
||||
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
return;
|
||||
}
|
||||
|
||||
Bitmap = bitmap;
|
||||
if (!isThumbnailLoaded)
|
||||
{
|
||||
MainWindowData.Visibility = Visibility.Visible;
|
||||
IsLoading = false;
|
||||
}
|
||||
});
|
||||
|
||||
return Task.WhenAll(thumbnailLoadTask, fullImageLoadTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<Window
|
||||
x:Class="Peek.UI.Views.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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"
|
||||
xmlns:ui="http://schemas.modernwpf.com/2019"
|
||||
xmlns:vm="clr-namespace:Peek.UI.ViewModels"
|
||||
Title="{Binding MainWindowData.Title, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Width="{Binding MainWindowData.Rectangle.Width, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Height="{Binding MainWindowData.Rectangle.Height, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
MinWidth="500"
|
||||
MinHeight="500"
|
||||
d:DataContext="{d:DesignInstance vm:MainViewModel}"
|
||||
ui:TitleBar.Background="{DynamicResource PrimaryBackgroundBrush}"
|
||||
ui:TitleBar.IsIconVisible="True"
|
||||
ui:WindowHelper.UseModernWindowStyle="True"
|
||||
Background="{DynamicResource PrimaryBackgroundBrush}"
|
||||
BorderThickness="1"
|
||||
Icon="/PowerToys.Peek.UI;component/Resources/Peek.ico"
|
||||
Left="{Binding MainWindowData.Rectangle.Left, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
ResizeMode="NoResize"
|
||||
Top="{Binding MainWindowData.Rectangle.Top, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Visibility="{Binding MainWindowData.Visibility, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
WindowStartupLocation="Manual"
|
||||
mc:Ignorable="d">
|
||||
<Grid>
|
||||
<ui:ProgressRing IsActive="{Binding IsLoading, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<!-- TODO: Create UI control that displays unsupported file gracefully -->
|
||||
<Image
|
||||
x:Name="ImageControl"
|
||||
Source="{Binding Bitmap, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
|
||||
Stretch="Uniform"
|
||||
StretchDirection="DownOnly"
|
||||
Visibility="{Binding IsImageReady, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
|
||||
</Grid>
|
||||
</Window>
|
||||
@@ -1,115 +0,0 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using interop;
|
||||
using ModernWpf.Controls;
|
||||
using Peek.UI.Extensions;
|
||||
using Peek.UI.Native;
|
||||
using Peek.UI.ViewModels;
|
||||
|
||||
namespace Peek.UI.Views
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window, IDisposable
|
||||
{
|
||||
private readonly MainViewModel _viewModel;
|
||||
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this.RoundCorners();
|
||||
|
||||
_viewModel = new MainViewModel(ImageControl);
|
||||
_viewModel.PropertyChanged += MainViewModel_PropertyChanged;
|
||||
|
||||
DataContext = _viewModel;
|
||||
|
||||
NativeEventWaiter.WaitForEventLoop(Constants.ShowPeekEvent(), OnPeekHotkey);
|
||||
|
||||
Loaded += MainWindow_Loaded;
|
||||
Closing += MainWindow_Closing;
|
||||
KeyDown += MainWindow_KeyDown;
|
||||
}
|
||||
|
||||
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_viewModel.MainWindowData.Visibility = Visibility.Collapsed;
|
||||
_viewModel.MainWindowData.TitleBarHeight = TitleBar.GetHeight(this);
|
||||
_viewModel.ImageControl = ImageControl;
|
||||
}
|
||||
|
||||
private void MainWindow_Closing(object? sender, System.ComponentModel.CancelEventArgs e)
|
||||
{
|
||||
_viewModel.MainWindowData.Visibility = Visibility.Collapsed;
|
||||
e.Cancel = true;
|
||||
}
|
||||
|
||||
private void MainWindow_KeyDown(object? sender, KeyEventArgs e)
|
||||
{
|
||||
if (!e.IsRepeat && _viewModel.CurrentSelectedFilePath != null)
|
||||
{
|
||||
switch (e.Key)
|
||||
{
|
||||
case Key.Left:
|
||||
_viewModel.CurrentSelectedFilePath = _viewModel.CurrentSelectedFilePath.GetPreviousOrLast();
|
||||
e.Handled = true;
|
||||
break;
|
||||
|
||||
case Key.Right:
|
||||
_viewModel.CurrentSelectedFilePath = _viewModel.CurrentSelectedFilePath.GetNextOrFirst();
|
||||
e.Handled = true;
|
||||
break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_viewModel.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected override void OnSourceInitialized(EventArgs e)
|
||||
{
|
||||
base.OnSourceInitialized(e);
|
||||
this.SetToolStyle();
|
||||
}
|
||||
|
||||
private async void MainViewModel_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
switch (e.PropertyName)
|
||||
{
|
||||
case nameof(MainViewModel.CurrentSelectedFilePath):
|
||||
if (_viewModel.CurrentSelectedFilePath != null)
|
||||
{
|
||||
await _viewModel.RenderImageToWindowAsync(_viewModel.CurrentSelectedFilePath.Value);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPeekHotkey()
|
||||
{
|
||||
if (IsActive && _viewModel.MainWindowData.Visibility == Visibility.Visible)
|
||||
{
|
||||
_viewModel.ClearSelection();
|
||||
}
|
||||
else
|
||||
{
|
||||
_viewModel.TryUpdateSelectedFilePaths();
|
||||
}
|
||||
|
||||
this.BringToForeground();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user