Remove Peek.UI.WPF project

This commit is contained in:
Samuel Chapleau
2023-01-17 09:46:58 -08:00
parent 645e798d97
commit f01de620ca
31 changed files with 0 additions and 1782 deletions

View File

@@ -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}

View File

@@ -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>

View File

@@ -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;
}
}
}

View File

@@ -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

View File

@@ -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;
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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));
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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; }
}
}

View File

@@ -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);
}
}

View File

@@ -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));
}
}
}

View File

@@ -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));
}
}
}
}
}

View File

@@ -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));
}
}
}
}
}

View File

@@ -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();
}
}
}

View File

@@ -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);
}
}

View File

@@ -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; }
}
}
}
}

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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);
}
}
}

View File

@@ -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>

View File

@@ -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();
}
}
}