mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 18:57:19 +02:00
Somil55/merge wpf to master (#3840)
* Basic WPF searchbox working * Updated key navigation and removed coldstart for searhbox * refactored and added code back in commented * Removed XAML Island references * Basic searchbox+listview working * Getting a bit more back * got color there * Result list bit better now * Added image loader for WPF Image * Partially got the context menus rendering again * adjusting coldstart to load, control will load with main form * getting context menus back * mouse over works now * Click now works, started to remove Win.XAML references * being a bit more forcusful on focus * Shadow text is not aligned * fixing focus if listbox was used * small tweak to fix shadow text * inputs don't work but gotta figure out why. commenting out * preview text * adding back in delay * fixed height issue * Applied the correct context button styles * Created custom ItemContainerStyle to fix the blue highlights behind the command buttons * Applied the correct highlight / mouseover styling * Removed vertical scrollbar in listview * fixed for alt-space prompt * Fixed right click focus issue * Somil55/wpf modifier keys (#3378) * Removed DPI change as it was not required * Global key hooks for context menu items * Updated Key for shell, folder and indexer plugin * Updated key mapping for indexer plugin * Somil55/wpf context menu selection (#3389) * Removed DPI change as it was not required * Global key hooks for context menu items * Updated Key for shell, folder and indexer plugin * Updated key mapping for indexer plugin * Add trigger to selection on tabbing * Minor shadow adjustments so its more similiar to default shell shadow. Added intro/outro animations * Added UWP-like scrollbar style for the results list * Fixed formating and naming * Removed Powerlauncher UI project * Update PowerToys.sln * Commented out scrollbar and fade in/out animations * Added missing features from UWP branch * Fixed formatting for Product.wxs * Add dragging to WPF window Co-authored-by: Clint Rutkas <clint@rutkas.com> Co-authored-by: Niels Laute <niels.laute@live.nl>
This commit is contained in:
committed by
GitHub
parent
5680a34ec1
commit
397b1533f0
@@ -1,7 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Windows.UI.Xaml.Media;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Wox.Infrastructure.Image
|
||||
{
|
||||
@@ -53,4 +54,4 @@ namespace Wox.Infrastructure.Image
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Wox.Infrastructure.Image
|
||||
{
|
||||
public interface IImageHashGenerator
|
||||
{
|
||||
string GetHashFromImage(ImageSource image);
|
||||
}
|
||||
public class ImageHashGenerator : IImageHashGenerator
|
||||
{
|
||||
public string GetHashFromImage(ImageSource imageSource)
|
||||
{
|
||||
if (!(imageSource is BitmapSource image))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (var outStream = new MemoryStream())
|
||||
{
|
||||
// PngBitmapEncoder enc2 = new PngBitmapEncoder();
|
||||
// enc2.Frames.Add(BitmapFrame.Create(tt));
|
||||
|
||||
var enc = new JpegBitmapEncoder();
|
||||
var bitmapFrame = BitmapFrame.Create(image);
|
||||
bitmapFrame.Freeze();
|
||||
enc.Frames.Add(bitmapFrame);
|
||||
enc.Save(outStream);
|
||||
var byteArray = outStream.GetBuffer();
|
||||
using (var sha1 = new SHA1CryptoServiceProvider())
|
||||
{
|
||||
var hash = Convert.ToBase64String(sha1.ComputeHash(byteArray));
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,10 @@ using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Wox.Infrastructure.Logger;
|
||||
using Wox.Infrastructure.Storage;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
||||
namespace Wox.Infrastructure.Image
|
||||
{
|
||||
@@ -14,6 +14,9 @@ namespace Wox.Infrastructure.Image
|
||||
{
|
||||
private static readonly ImageCache ImageCache = new ImageCache();
|
||||
private static BinaryStorage<ConcurrentDictionary<string, int>> _storage;
|
||||
private static readonly ConcurrentDictionary<string, string> GuidToKey = new ConcurrentDictionary<string, string>();
|
||||
private static IImageHashGenerator _hashGenerator;
|
||||
|
||||
|
||||
private static readonly string[] ImageExtensions =
|
||||
{
|
||||
@@ -30,11 +33,13 @@ namespace Wox.Infrastructure.Image
|
||||
public static void Initialize()
|
||||
{
|
||||
_storage = new BinaryStorage<ConcurrentDictionary<string, int>>("Image");
|
||||
_hashGenerator = new ImageHashGenerator();
|
||||
ImageCache.Usage = _storage.TryLoad(new ConcurrentDictionary<string, int>());
|
||||
|
||||
foreach (var icon in new[] { Constant.DefaultIcon, Constant.ErrorIcon })
|
||||
{
|
||||
ImageSource img = new BitmapImage(new Uri(icon));
|
||||
img.Freeze();
|
||||
ImageCache[icon] = img;
|
||||
}
|
||||
Task.Run(() =>
|
||||
@@ -96,6 +101,7 @@ namespace Wox.Infrastructure.Image
|
||||
if (path.StartsWith("data:", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var imageSource = new BitmapImage(new Uri(path));
|
||||
imageSource.Freeze();
|
||||
return new ImageResult(imageSource, ImageType.Data);
|
||||
}
|
||||
|
||||
@@ -150,6 +156,11 @@ namespace Wox.Infrastructure.Image
|
||||
image = ImageCache[Constant.ErrorIcon];
|
||||
path = Constant.ErrorIcon;
|
||||
}
|
||||
|
||||
if (type != ImageType.Error)
|
||||
{
|
||||
image.Freeze();
|
||||
}
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
@@ -161,23 +172,44 @@ namespace Wox.Infrastructure.Image
|
||||
return new ImageResult(image, type);
|
||||
}
|
||||
|
||||
private static bool EnableImageHash = true;
|
||||
|
||||
public static ImageSource Load(string path, bool loadFullImage = false)
|
||||
{
|
||||
var imageResult = LoadInternal(path, loadFullImage);
|
||||
|
||||
var img = imageResult.ImageSource;
|
||||
if (imageResult.ImageType != ImageType.Error && imageResult.ImageType != ImageType.Cache)
|
||||
{
|
||||
{ // we need to get image hash
|
||||
string hash = EnableImageHash ? _hashGenerator.GetHashFromImage(img) : null;
|
||||
if (hash != null)
|
||||
{
|
||||
if (GuidToKey.TryGetValue(hash, out string key))
|
||||
{ // image already exists
|
||||
img = ImageCache[key];
|
||||
}
|
||||
else
|
||||
{ // new guid
|
||||
GuidToKey[hash] = path;
|
||||
}
|
||||
}
|
||||
|
||||
// update cache
|
||||
ImageCache[path] = img;
|
||||
}
|
||||
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
private static BitmapImage LoadFullImage(string path)
|
||||
{
|
||||
BitmapImage image = new BitmapImage(new Uri(path));
|
||||
BitmapImage image = new BitmapImage();
|
||||
image.BeginInit();
|
||||
image.CacheOption = BitmapCacheOption.OnLoad;
|
||||
image.UriSource = new Uri(path);
|
||||
image.EndInit();
|
||||
return image;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,178 +1,153 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows;
|
||||
using Windows.Storage.Streams;
|
||||
using BitmapSourceWPF = System.Windows.Media.Imaging.BitmapSource;
|
||||
using BitmapImageUWP = Windows.UI.Xaml.Media.Imaging.BitmapImage;
|
||||
|
||||
namespace Wox.Infrastructure.Image
|
||||
{
|
||||
[Flags]
|
||||
public enum ThumbnailOptions
|
||||
{
|
||||
None = 0x00,
|
||||
BiggerSizeOk = 0x01,
|
||||
InMemoryOnly = 0x02,
|
||||
IconOnly = 0x04,
|
||||
ThumbnailOnly = 0x08,
|
||||
InCacheOnly = 0x10,
|
||||
}
|
||||
|
||||
public class WindowsThumbnailProvider
|
||||
{
|
||||
// Based on https://stackoverflow.com/questions/21751747/extract-thumbnail-for-any-file-in-windows
|
||||
|
||||
private const string IShellItem2Guid = "7E9FB0D3-919F-4307-AB2E-9B1860310C93";
|
||||
|
||||
[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("gdi32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool DeleteObject(IntPtr hObject);
|
||||
|
||||
[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);
|
||||
};
|
||||
|
||||
internal enum SIGDN : uint
|
||||
{
|
||||
NORMALDISPLAY = 0,
|
||||
PARENTRELATIVEPARSING = 0x80018001,
|
||||
PARENTRELATIVEFORADDRESSBAR = 0x8001c001,
|
||||
DESKTOPABSOLUTEPARSING = 0x80028000,
|
||||
PARENTRELATIVEEDITING = 0x80031001,
|
||||
DESKTOPABSOLUTEEDITING = 0x8004c000,
|
||||
FILESYSPATH = 0x80058000,
|
||||
URL = 0x80068000
|
||||
}
|
||||
|
||||
internal 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)
|
||||
}
|
||||
|
||||
[ComImportAttribute()]
|
||||
[GuidAttribute("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
|
||||
[InterfaceTypeAttribute(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; } }
|
||||
};
|
||||
|
||||
public static BitmapImageUWP ByteToImage(byte[] imageData)
|
||||
{
|
||||
using (InMemoryRandomAccessStream ms = new InMemoryRandomAccessStream())
|
||||
{
|
||||
using (DataWriter writer = new DataWriter(ms.GetOutputStreamAt(0)))
|
||||
{
|
||||
writer.WriteBytes(imageData);
|
||||
writer.StoreAsync().GetResults();
|
||||
}
|
||||
BitmapImageUWP image = new BitmapImageUWP();
|
||||
image.SetSource(ms);
|
||||
return image;
|
||||
}
|
||||
}
|
||||
|
||||
public static BitmapImageUWP GetThumbnail(string fileName, int width, int height, ThumbnailOptions options)
|
||||
{
|
||||
IntPtr hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options);
|
||||
try
|
||||
{
|
||||
byte[] data;
|
||||
BitmapSourceWPF bitmapSourceWPF = Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
|
||||
PngBitmapEncoder encoder = new PngBitmapEncoder();
|
||||
encoder.Frames.Add(BitmapFrame.Create(bitmapSourceWPF));
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
encoder.Save(ms);
|
||||
data = ms.ToArray();
|
||||
}
|
||||
return ByteToImage(data);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// delete HBitmap to avoid memory leaks
|
||||
DeleteObject(hBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
private static IntPtr GetHBitmap(string fileName, int width, int height, ThumbnailOptions options)
|
||||
{
|
||||
IShellItem nativeShellItem;
|
||||
Guid shellItem2Guid = new Guid(IShellItem2Guid);
|
||||
int retCode = SHCreateItemFromParsingName(fileName, IntPtr.Zero, ref shellItem2Guid, out nativeShellItem);
|
||||
|
||||
if (retCode != 0)
|
||||
throw Marshal.GetExceptionForHR(retCode);
|
||||
|
||||
NativeSize nativeSize = new NativeSize
|
||||
{
|
||||
Width = width,
|
||||
Height = height
|
||||
};
|
||||
|
||||
IntPtr hBitmap;
|
||||
HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(nativeSize, options, out hBitmap);
|
||||
|
||||
// if extracting image thumbnail and failed, extract shell icon
|
||||
if (options == ThumbnailOptions.ThumbnailOnly && hr == HResult.ExtractionFailed)
|
||||
{
|
||||
hr = ((IShellItemImageFactory) nativeShellItem).GetImage(nativeSize, ThumbnailOptions.IconOnly, out hBitmap);
|
||||
}
|
||||
|
||||
Marshal.ReleaseComObject(nativeShellItem);
|
||||
|
||||
if (hr == HResult.Ok) return hBitmap;
|
||||
|
||||
throw new COMException($"Error while extracting thumbnail for {fileName}", Marshal.GetExceptionForHR((int)hr));
|
||||
}
|
||||
}
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.IO;
|
||||
using System.Windows.Interop;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows;
|
||||
|
||||
namespace Wox.Infrastructure.Image
|
||||
{
|
||||
[Flags]
|
||||
public enum ThumbnailOptions
|
||||
{
|
||||
None = 0x00,
|
||||
BiggerSizeOk = 0x01,
|
||||
InMemoryOnly = 0x02,
|
||||
IconOnly = 0x04,
|
||||
ThumbnailOnly = 0x08,
|
||||
InCacheOnly = 0x10,
|
||||
}
|
||||
|
||||
public class WindowsThumbnailProvider
|
||||
{
|
||||
// Based on https://stackoverflow.com/questions/21751747/extract-thumbnail-for-any-file-in-windows
|
||||
|
||||
private const string IShellItem2Guid = "7E9FB0D3-919F-4307-AB2E-9B1860310C93";
|
||||
|
||||
[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("gdi32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool DeleteObject(IntPtr hObject);
|
||||
|
||||
[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);
|
||||
};
|
||||
|
||||
internal enum SIGDN : uint
|
||||
{
|
||||
NORMALDISPLAY = 0,
|
||||
PARENTRELATIVEPARSING = 0x80018001,
|
||||
PARENTRELATIVEFORADDRESSBAR = 0x8001c001,
|
||||
DESKTOPABSOLUTEPARSING = 0x80028000,
|
||||
PARENTRELATIVEEDITING = 0x80031001,
|
||||
DESKTOPABSOLUTEEDITING = 0x8004c000,
|
||||
FILESYSPATH = 0x80058000,
|
||||
URL = 0x80068000
|
||||
}
|
||||
|
||||
internal 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)
|
||||
}
|
||||
|
||||
[ComImportAttribute()]
|
||||
[GuidAttribute("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
|
||||
[InterfaceTypeAttribute(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; } }
|
||||
};
|
||||
|
||||
|
||||
public static BitmapSource GetThumbnail(string fileName, int width, int height, ThumbnailOptions options)
|
||||
{
|
||||
IntPtr hBitmap = GetHBitmap(Path.GetFullPath(fileName), width, height, options);
|
||||
|
||||
try
|
||||
{
|
||||
return Imaging.CreateBitmapSourceFromHBitmap(hBitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
|
||||
}
|
||||
finally
|
||||
{
|
||||
// delete HBitmap to avoid memory leaks
|
||||
DeleteObject(hBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
private static IntPtr GetHBitmap(string fileName, int width, int height, ThumbnailOptions options)
|
||||
{
|
||||
IShellItem nativeShellItem;
|
||||
Guid shellItem2Guid = new Guid(IShellItem2Guid);
|
||||
int retCode = SHCreateItemFromParsingName(fileName, IntPtr.Zero, ref shellItem2Guid, out nativeShellItem);
|
||||
|
||||
if (retCode != 0)
|
||||
throw Marshal.GetExceptionForHR(retCode);
|
||||
|
||||
NativeSize nativeSize = new NativeSize
|
||||
{
|
||||
Width = width,
|
||||
Height = height
|
||||
};
|
||||
|
||||
IntPtr hBitmap;
|
||||
HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(nativeSize, options, out hBitmap);
|
||||
|
||||
// if extracting image thumbnail and failed, extract shell icon
|
||||
if (options == ThumbnailOptions.ThumbnailOnly && hr == HResult.ExtractionFailed)
|
||||
{
|
||||
hr = ((IShellItemImageFactory)nativeShellItem).GetImage(nativeSize, ThumbnailOptions.IconOnly, out hBitmap);
|
||||
}
|
||||
|
||||
Marshal.ReleaseComObject(nativeShellItem);
|
||||
|
||||
if (hr == HResult.Ok) return hBitmap;
|
||||
|
||||
throw new COMException($"Error while extracting thumbnail for {fileName}", Marshal.GetExceptionForHR((int)hr));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user