Peek (#22498)
* Add peek dll project
* add spacebar preview and launch on hotkey press
* add todo
* add process handle to handle continuous press of hotkey
* add tool to stop all powertoys processes
* Add a blank Peek page and update nav menu
* Add some initial content to Peek page including a toggle
* refactor settings parsing
* rename spacebar peek to peek viewer
* rename script to stop powertoys processes
* remove tool
* Adding FileUtils for retrieving selected file in File Explorer
* Remove unnecessary SndPeekSettings
* Add shortcut setting
* Set the shortcut to ctrl+space
* Launching viewer with selected FE file
* Add PeekUI WinUI3 project with interop events
* Moving FileTypeUtils into PeekFileUtils project
* execute winui3 app on hotkey
* Fix paths with spaces
* remove winui3 project
* Resolve comment
* add wpf app with toggle visibility on hotkey
* fix visibility on startup
* remove window properties and add todos
* Fixed hidden extension and system file handling
* wip
* Add working WPF app with FileExplorer querying
* remove c++ projects
* Move native awaiter
* Working Image control with image files
* Resize and move window based on explorer monitor
* Image render, window positioning and sizing clean up
* add window management logic and selection logic
* add extension methods to add circular iterating capability to linkedlistnode
* Add OnArrowKeyPresshandler
* Added titlebar with file name and scaling with titlebar height
* fix flashing window on startup and process kept alive when powertoys exits
* remove wait for debugger loop in ui
* Add KeyIsDown method
* Fix KeyDown issue with Key handled and check for repeat
* Add thumbnail logic
* Add all folder items if only one item is selected
* File type helper
* Using hresult
* Add cancellation and rotation handling
* Use extension instead of path
* fIX CONFLICTS
* Fixing some file type checks
* Add new icon for Peek
* Update page with the new Peek icon
* Initialize IsEnabled and hook ActivationShortcut to dllmain
* add icon to taskbar and titlebar
* Add theme sensitive backgrounds
* rename event handlers
* add settings image
* Move window data into obserable object
* Refactor viewmodel, interop and helpers
* Clean up
* Add loading spinner
* Add todos
* Fix conflicts
* Move native code into its own folder
* Add peek to installer
* Fix building peek and peekui projects
* Replace UWP namespaces to WinAppSDK
* Working WASDK placeholder project
* Add exit when powertoys runner exit
* Working winui3 with image display
* Add WIC project with <TreatWarningAsErros> false for now
* Fit content to window
* Use Size from Windows.Foundation
* Change order
* Add some todos
* Refactored native/interop code and added helpers to imagepreviewer
* Rename projects
* Move some code
* Remove using
Co-authored-by: Michael Salmon <miksalmon@users.noreply.github.com>
Co-authored-by: Michael Salmon 🐟 <michaelpsalmon@outlook.com>
Co-authored-by: Alireza Ebadi Ghajari <alirezae@microsoft.com>
Co-authored-by: Jessie Su <Jessie.Su@microsoft.com>
Co-authored-by: sujessie <102062556+sujessie@users.noreply.github.com>
101
PowerToys.sln
@ -468,7 +468,21 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FileLocksmithLibInterop", "
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GPOWrapper", "src\common\GPOWrapper\GPOWrapper.vcxproj", "{E599C30B-9DC8-4E5A-BF27-93D4CCEDE788}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GPOWrapperProjection", "src\common\GPOWrapperProjection\GPOWrapperProjection.csproj", "{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97}"
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GPOWrapperProjection", "src\common\GPOWrapperProjection\GPOWrapperProjection.csproj", "{00EE9BA6-4E8F-43CA-960D-D4882F0FBB97}"
|
||||
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}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Peek.Common", "src\modules\peek\Peek.Common\Peek.Common.csproj", "{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Peek.FilePreviewer", "src\modules\peek\Peek.FilePreviewer\Peek.FilePreviewer.csproj", "{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WIC", "src\modules\peek\WIC\WIC.csproj", "{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@ -1909,6 +1923,84 @@ 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|x64
|
||||
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Debug|ARM64.Build.0 = Debug|x64
|
||||
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Debug|x64.Build.0 = Debug|x64
|
||||
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Debug|x86.Build.0 = Debug|x64
|
||||
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Release|ARM64.ActiveCfg = Release|x64
|
||||
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Release|ARM64.Build.0 = Release|x64
|
||||
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Release|x64.ActiveCfg = Release|x64
|
||||
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Release|x64.Build.0 = Release|x64
|
||||
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Release|x86.ActiveCfg = Release|x64
|
||||
{A1425B53-3D61-4679-8623-E64A0D3D0A48}.Release|x86.Build.0 = Release|x64
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|ARM64.Deploy.0 = Debug|ARM64
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|x64.Build.0 = Debug|x64
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|x64.Deploy.0 = Debug|x64
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|x86.Build.0 = Debug|x86
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Debug|x86.Deploy.0 = Debug|x86
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|ARM64.Deploy.0 = Release|ARM64
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|x64.ActiveCfg = Release|x64
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|x64.Build.0 = Release|x64
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|x64.Deploy.0 = Release|x64
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|x86.ActiveCfg = Release|x86
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|x86.Build.0 = Release|x86
|
||||
{9D7A6DE0-7D27-424D-ABAE-41B2161F9A03}.Release|x86.Deploy.0 = Release|x86
|
||||
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Debug|x64.Build.0 = Debug|x64
|
||||
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Debug|x86.Build.0 = Debug|x64
|
||||
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Release|x64.ActiveCfg = Release|x64
|
||||
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Release|x64.Build.0 = Release|x64
|
||||
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Release|x86.ActiveCfg = Release|x64
|
||||
{17A99C7C-0BFF-45BB-A9FD-63A0DDC105BB}.Release|x86.Build.0 = Release|x64
|
||||
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Debug|x64.Build.0 = Debug|x64
|
||||
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Debug|x86.Build.0 = Debug|x64
|
||||
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Release|x64.ActiveCfg = Release|x64
|
||||
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Release|x64.Build.0 = Release|x64
|
||||
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Release|x86.ActiveCfg = Release|x64
|
||||
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC}.Release|x86.Build.0 = Release|x64
|
||||
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Debug|ARM64.ActiveCfg = Debug|ARM64
|
||||
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Debug|ARM64.Build.0 = Debug|ARM64
|
||||
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Debug|x64.Build.0 = Debug|x64
|
||||
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Debug|x86.ActiveCfg = Debug|x64
|
||||
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Debug|x86.Build.0 = Debug|x64
|
||||
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Release|ARM64.ActiveCfg = Release|ARM64
|
||||
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Release|ARM64.Build.0 = Release|ARM64
|
||||
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Release|x64.ActiveCfg = Release|x64
|
||||
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Release|x64.Build.0 = Release|x64
|
||||
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Release|x86.ActiveCfg = Release|x64
|
||||
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF}.Release|x86.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -2071,6 +2163,13 @@ Global
|
||||
{C604B37E-9D0E-4484-8778-E8B31B0E1B3A} = {AB82E5DD-C32D-4F28-9746-2C780846188E}
|
||||
{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}
|
||||
{AA9F0AF8-7924-4D59-BAA1-E36F1304E0DC} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
|
||||
{21B69DE5-59FD-4C5D-A142-EF1C1C430EAF} = {17B4FA70-001E-4D33-BBBB-0D142DBC2E20}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C3A2F9D1-7930-4EF4-A6FC-7EE0A99821D0}
|
||||
|
@ -17,6 +17,7 @@
|
||||
<?define AlwaysOnTopProjectName="AlwaysOnTop"?>
|
||||
<?define MeasureToolProjectName="MeasureTool"?>
|
||||
<?define HostsProjectName="Hosts"?>
|
||||
<?define PeekProjectName="Peek"?>
|
||||
|
||||
<?define RepoDir="$(var.ProjectDir)..\..\" ?>
|
||||
<?if $(var.Platform) = x64?>
|
||||
@ -53,7 +54,7 @@
|
||||
|
||||
<?define SettingsV2Files=backup_restore_settings.json;Ijwhost.dll;ColorCode.Core.dll;ColorCode.WinUI.dll;CommunityToolkit.Common.dll;CommunityToolkit.Labs.WinUI.SettingsControls.dll;CommunityToolkit.WinUI.dll;CommunityToolkit.WinUI.UI.Controls.Core.dll;CommunityToolkit.WinUI.UI.Controls.DataGrid.dll;CommunityToolkit.WinUI.UI.Controls.Input.dll;CommunityToolkit.WinUI.UI.Controls.Layout.dll;CommunityToolkit.WinUI.UI.Controls.Markdown.dll;CommunityToolkit.WinUI.UI.Controls.Media.dll;CommunityToolkit.WinUI.UI.Controls.Primitives.dll;CommunityToolkit.WinUI.UI.dll;icon.ico;Microsoft.Graphics.Canvas.Interop.dll;Microsoft.InteractiveExperiences.Projection.dll;Microsoft.Windows.ApplicationModel.DynamicDependency.Projection.dll;Microsoft.Windows.ApplicationModel.Resources.Projection.dll;Microsoft.Windows.ApplicationModel.WindowsAppRuntime.Projection.dll;Microsoft.Windows.AppLifecycle.Projection.dll;Microsoft.Windows.SDK.NET.dll;Microsoft.Windows.System.Power.Projection.dll;Microsoft.WindowsAppRuntime.Bootstrap.Net.dll;Microsoft.WinUI.dll;Microsoft.Xaml.Interactions.dll;Microsoft.Xaml.Interactivity.dll;PowerToys.ManagedCommon.dll;PowerToys.ManagedTelemetry.dll;PowerToys.Settings.deps.json;PowerToys.Settings.dll;PowerToys.Settings.exe;PowerToys.Settings.runtimeconfig.json;PowerToys.Settings.UI.Lib.dll;resources.pri;System.CodeDom.dll;System.IO.Abstractions.dll;WinRT.Runtime.dll;Microsoft.Graphics.Canvas.dll;System.Management.dll;PowerToys.GPOWrapper.dll?>
|
||||
|
||||
<?define SettingsV2AssetsModulesFiles=ColorPicker.png;FancyZones.png;FileLocksmith.png;AlwaysOnTop.png;HostsFileEditor.png;Awake.png;ImageResizer.png;KBM.png;MouseUtils.png;PowerAccent.png;PowerOCR.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ScreenRuler.png;ShortcutGuide.png;VideoConference.png?>
|
||||
<?define SettingsV2AssetsModulesFiles=ColorPicker.png;FancyZones.png;FileLocksmith.png;AlwaysOnTop.png;HostsFileEditor.png;Awake.png;ImageResizer.png;KBM.png;MouseUtils.png;PowerAccent.png;PowerOCR.png;PowerLauncher.png;PowerPreview.png;PowerRename.png;PT.png;ScreenRuler.png;ShortcutGuide.png;VideoConference.png;Peek.png?>
|
||||
|
||||
<?define SettingsV2OOBEAssetsModulesFiles=ColorPicker.gif;AlwaysOnTop.png;HostsFileEditor.png;Awake.png;FancyZones.gif;FileExplorer.png;FileLocksmith.gif;ImageResizer.gif;KBM.gif;MouseUtils.gif;PowerAccent.gif;PowerOCR.gif;PowerRename.gif;Run.gif;ScreenRuler.gif;OOBEShortcutGuide.png;VideoConferenceMute.png;OOBEPTHero.png?>
|
||||
|
||||
@ -542,6 +543,12 @@
|
||||
<Directory Id="ColorPickerResourcesFolder" Name="Resources"/>
|
||||
</Directory>
|
||||
|
||||
<!-- Peek -->
|
||||
<Directory Id="PeekInstallFolder" Name="$(var.PeekProjectName)">
|
||||
<Directory Id="PeekResourcesFolder" Name="Resources"/>
|
||||
<Directory Id="PeekAssetsFolder" Name="Assets" />
|
||||
</Directory>
|
||||
|
||||
<!-- Mouse Utils -->
|
||||
<Directory Id="MouseUtilsInstallFolder" Name="$(var.MouseUtilsProjectName)">
|
||||
</Directory>
|
||||
@ -1032,6 +1039,31 @@
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- Peek -->
|
||||
<DirectoryRef Id="PeekInstallFolder" FileSource="$(var.BinX64Dir)modules\$(var.PeekProjectName)">
|
||||
<!-- !Warning! Make sure to change Component Guid if you update the file list -->
|
||||
<Component Id="Module_Peek" Guid="6520F12A-C255-4C3E-862B-0589897BEE21" Win64="yes">
|
||||
<?foreach File in PowerToys.Peek.dll;PowerToys.Peek.UI.exe;PowerToys.Peek.UI.dll;PowerToys.Peek.UI.deps.json;PowerToys.Peek.UI.runtimeconfig.json;PowerToys.Interop.dll;PowerToys.ManagedTelemetry.dll;PowerToys.ManagedCommon.dll;ControlzEx.dll;Microsoft.Xaml.Behaviors.dll;ModernWpf.Controls.dll;ModernWpf.dll;PowerToys.Common.UI.dll;WinRT.Runtime.dll;Microsoft.Windows.SDK.NET.dll;WpfScreenHelper.dll?>
|
||||
<File Id="PeekFile_$(var.File)" Source="$(var.BinX64Dir)modules\$(var.PeekProjectName)\$(var.File)" />
|
||||
<?endforeach?>
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- Peek Resources -->
|
||||
<DirectoryRef Id="PeekResourcesFolder" FileSource="$(var.BinX64Dir)modules\$(var.PeekProjectName)\Resources">
|
||||
<Component Id="Module_Peek_Icon">
|
||||
<File Id="PeekFile_icon.ico" Source="$(var.BinX64Dir)modules\$(var.PeekProjectName)\Resources\Peek.ico" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- Peek Assets -->
|
||||
<DirectoryRef Id="PeekAssetsFolder" FileSource="$(var.BinX64Dir)modules\$(var.PeekProjectName)\Assets">
|
||||
<!-- !Warning! Make sure to change Component Guid if you update the file list -->
|
||||
<Component Id="Module_Peek_Assets" Guid="7E781723-60AB-4027-B634-AFCEDDB2B1CD" Win64="yes">
|
||||
<File Source="$(var.BinX64Dir)modules\$(var.PeekProjectName)\Assets\error.png" />
|
||||
</Component>
|
||||
</DirectoryRef>
|
||||
|
||||
<!-- KBM -->
|
||||
<DirectoryRef Id="KeyboardManagerInstallFolder" FileSource="$(var.BinDir)modules\$(var.KeyboardManagerProjectName)\">
|
||||
<Component Id="Module_KeyboardManager" Win64="yes">
|
||||
@ -1332,6 +1364,9 @@
|
||||
<ComponentRef Id="Module_KeyboardManager_Editor" />
|
||||
<ComponentRef Id="Module_KeyboardManager_Engine" />
|
||||
<ComponentRef Id="Module_PowerOCR" />
|
||||
<ComponentRef Id="Module_Peek" />
|
||||
<ComponentRef Id="Module_Peek_Icon"/>
|
||||
<ComponentRef Id="Module_Peek_Assets" />
|
||||
<ComponentRef Id="Module_ColorPicker" />
|
||||
<ComponentRef Id="Module_ColorPicker_Icon"/>
|
||||
<ComponentRef Id="Module_ColorPicker_Cursor"/>
|
||||
@ -1407,7 +1442,7 @@
|
||||
<Fragment>
|
||||
<!-- Resource directories should be added only if the installer is built on the build farm -->
|
||||
<?ifdef env.IsPipeline?>
|
||||
<?foreach ParentDirectory in LauncherInstallFolder;FancyZonesInstallFolder;ImageResizerInstallFolder;ColorPickerInstallFolder;FileExplorerPreviewInstallFolder;HistoryPluginFolder;CalculatorPluginFolder;FolderPluginFolder;ProgramPluginFolder;ShellPluginFolder;IndexerPluginFolder;UnitConverterPluginFolder;UriPluginFolder;WindowWalkerPluginFolder;OneNotePluginFolder;RegistryPluginFolder;VSCodeWorkspacesPluginFolder;ServicePluginFolder;SystemPluginFolder;TimeDatePluginFolder;TimeZonePluginFolder;WindowsSettingsPluginFolder;WindowsTerminalPluginFolder;WebSearchPluginFolder?>
|
||||
<?foreach ParentDirectory in LauncherInstallFolder;FancyZonesInstallFolder;ImageResizerInstallFolder;ColorPickerInstallFolder;PeekInstallFolder;FileExplorerPreviewInstallFolder;HistoryPluginFolder;CalculatorPluginFolder;FolderPluginFolder;ProgramPluginFolder;ShellPluginFolder;IndexerPluginFolder;UnitConverterPluginFolder;UriPluginFolder;WindowWalkerPluginFolder;OneNotePluginFolder;RegistryPluginFolder;VSCodeWorkspacesPluginFolder;ServicePluginFolder;SystemPluginFolder;TimeDatePluginFolder;TimeZonePluginFolder;WindowsSettingsPluginFolder;WindowsTerminalPluginFolder;WebSearchPluginFolder?>
|
||||
<DirectoryRef Id="$(var.ParentDirectory)">
|
||||
<!-- Resource file directories -->
|
||||
<?foreach Language in $(var.LocLanguageList)?>
|
||||
@ -1561,6 +1596,12 @@
|
||||
Guid="$(var.CompGUIDPrefix)03">
|
||||
<File Id="ColorPicker_$(var.IdSafeLanguage)_File" Source="$(var.BinDir)modules\$(var.ColorPickerProjectName)\$(var.Language)\PowerToys.ColorPickerUI.resources.dll" />
|
||||
</Component>
|
||||
<Component
|
||||
Id="Peek_$(var.IdSafeLanguage)_Component"
|
||||
Directory="Resource$(var.IdSafeLanguage)PeekInstallFolder"
|
||||
Guid="$(var.CompGUIDPrefix)03">
|
||||
<File Id="Peek_$(var.IdSafeLanguage)_File" Source="$(var.BinX64Dir)modules\$(var.PeekProjectName)\$(var.Language)\PowerToys.Peek.UI.resources.dll" />
|
||||
</Component>
|
||||
<Component
|
||||
Id="MarkdownPreviewHandler_$(var.IdSafeLanguage)_Component"
|
||||
Directory="Resource$(var.IdSafeLanguage)FileExplorerPreviewInstallFolder"
|
||||
|
@ -1230,7 +1230,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
|
||||
}
|
||||
processes.resize(bytes / sizeof(processes[0]));
|
||||
|
||||
std::array<std::wstring_view, 9> processesToTerminate = {
|
||||
std::array<std::wstring_view, 10> processesToTerminate = {
|
||||
L"PowerToys.PowerLauncher.exe",
|
||||
L"PowerToys.Settings.exe",
|
||||
L"PowerToys.Awake.exe",
|
||||
@ -1239,6 +1239,7 @@ UINT __stdcall TerminateProcessesCA(MSIHANDLE hInstall)
|
||||
L"PowerToys.FileLocksmithUI.exe",
|
||||
L"PowerToys.ColorPickerUI.exe",
|
||||
L"PowerToys.AlwaysOnTop.exe",
|
||||
L"PowerToys.PeekUI.exe",
|
||||
L"PowerToys.exe"
|
||||
};
|
||||
|
||||
|
@ -203,6 +203,10 @@ public
|
||||
return gcnew String(CommonSharedConstants::AWAKE_EXIT_EVENT);
|
||||
}
|
||||
|
||||
static String^ ShowPeekEvent() {
|
||||
return gcnew String(CommonSharedConstants::SHOW_PEEK_SHARED_EVENT);
|
||||
}
|
||||
|
||||
static String ^ PowerAccentExitEvent() {
|
||||
return gcnew String(CommonSharedConstants::POWERACCENT_EXIT_EVENT);
|
||||
}
|
||||
|
@ -44,6 +44,9 @@ namespace CommonSharedConstants
|
||||
// Path to the event used by PowerOCR
|
||||
const wchar_t SHOW_POWEROCR_SHARED_EVENT[] = L"Local\\PowerOCREvent-dc864e06-e1af-4ecc-9078-f98bee745e3a";
|
||||
|
||||
// Path to the event used to show Peek
|
||||
const wchar_t SHOW_PEEK_SHARED_EVENT[] = L"Local\\ShowPeekEvent";
|
||||
|
||||
// Max DWORD for key code to disable keys.
|
||||
const DWORD VK_DISABLED = 0x100;
|
||||
}
|
||||
|
36
src/modules/peek/Peek.Common/Models/File.cs
Normal file
@ -0,0 +1,36 @@
|
||||
// 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.Common.Models
|
||||
{
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Storage;
|
||||
|
||||
#nullable enable
|
||||
|
||||
public class File
|
||||
{
|
||||
private StorageFile? storageFile;
|
||||
|
||||
public File(string path)
|
||||
{
|
||||
Path = path;
|
||||
}
|
||||
|
||||
public string Path { get; init; }
|
||||
|
||||
public string Extension => System.IO.Path.GetExtension(Path);
|
||||
|
||||
public async Task<StorageFile> GetStorageFileAsync()
|
||||
{
|
||||
if (storageFile == null)
|
||||
{
|
||||
storageFile = await StorageFile.GetFileFromPathAsync(Path);
|
||||
}
|
||||
|
||||
return storageFile;
|
||||
}
|
||||
}
|
||||
}
|
24
src/modules/peek/Peek.Common/Models/HResult.cs
Normal file
@ -0,0 +1,24 @@
|
||||
// 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.Common.Models
|
||||
{
|
||||
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),
|
||||
}
|
||||
}
|
41
src/modules/peek/Peek.Common/Models/IShellItem.cs
Normal file
@ -0,0 +1,41 @@
|
||||
// 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.Common.Models
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[ComImport]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
[Guid("43826d1e-e718-42ee-bc55-a1e261c37bfe")]
|
||||
public 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);
|
||||
}
|
||||
|
||||
public enum Sigdn : uint
|
||||
{
|
||||
NormalDisplay = 0,
|
||||
ParentRelativeParsing = 0x80018001,
|
||||
ParentRelativeForAddressBar = 0x8001c001,
|
||||
DesktopAbsoluteParsing = 0x80028000,
|
||||
ParentRelativeEditing = 0x80031001,
|
||||
DesktopAbsoluteEditing = 0x8004c000,
|
||||
FileSysPath = 0x80058000,
|
||||
Url = 0x80068000,
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
// 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.Common.Models
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
[ComImport]
|
||||
[Guid("bcc18b79-ba16-442f-80c4-8a59c30c463b")]
|
||||
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
||||
public interface IShellItemImageFactory
|
||||
{
|
||||
[PreserveSig]
|
||||
HResult GetImage(
|
||||
[In, MarshalAs(UnmanagedType.Struct)] NativeSize size,
|
||||
[In] ThumbnailOptions flags,
|
||||
[Out] out IntPtr phbm);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
public struct NativeSize
|
||||
{
|
||||
private int width;
|
||||
private int height;
|
||||
|
||||
public int Width
|
||||
{
|
||||
set { width = value; }
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
set { height = value; }
|
||||
}
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ThumbnailOptions
|
||||
{
|
||||
None = 0x00,
|
||||
BiggerSizeOk = 0x01,
|
||||
InMemoryOnly = 0x02,
|
||||
IconOnly = 0x04,
|
||||
ThumbnailOnly = 0x08,
|
||||
InCacheOnly = 0x10,
|
||||
ScaleUp = 0x100,
|
||||
}
|
||||
}
|
15
src/modules/peek/Peek.Common/Peek.Common.csproj
Normal file
@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<RootNamespace>Peek.Common</RootNamespace>
|
||||
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.1.5" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22000.194" />
|
||||
</ItemGroup>
|
||||
</Project>
|
27
src/modules/peek/Peek.FilePreviewer/FilePreview.xaml
Normal file
@ -0,0 +1,27 @@
|
||||
<!-- Copyright (c) Microsoft Corporation and Contributors. -->
|
||||
<!-- Licensed under the MIT License. -->
|
||||
|
||||
<UserControl
|
||||
x:Class="Peek.FilePreviewer.FilePreview"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:animations="using:CommunityToolkit.WinUI.UI.Animations"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Peek.FilePreviewer"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:media="using:CommunityToolkit.WinUI.UI.Media"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid>
|
||||
<ProgressRing
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
IsActive="{x:Bind IsPreviewLoading(Previewer.Preview), Mode=OneWay}" />
|
||||
|
||||
<Image x:Name="PreviewImage" Source="{x:Bind Previewer.Preview, Mode=OneWay}" />
|
||||
|
||||
<!-- TODO: Add WebView2 support. -->
|
||||
|
||||
<!-- TODO: Add UnsupportedFilePreview control -->
|
||||
</Grid>
|
||||
</UserControl>
|
89
src/modules/peek/Peek.FilePreviewer/FilePreview.xaml.cs
Normal file
@ -0,0 +1,89 @@
|
||||
// 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.FilePreviewer
|
||||
{
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using CommunityToolkit.WinUI.UI.Media.Pipelines;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
using Peek.Common.Models;
|
||||
using Peek.FilePreviewer.Models;
|
||||
using Peek.FilePreviewer.Previewers;
|
||||
using Windows.Foundation;
|
||||
|
||||
[INotifyPropertyChanged]
|
||||
public sealed partial class FilePreview : UserControl
|
||||
{
|
||||
public event EventHandler<PreviewSizeChangedArgs>? PreviewSizeChanged;
|
||||
|
||||
public static readonly DependencyProperty FilesProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(File),
|
||||
typeof(File),
|
||||
typeof(FilePreview),
|
||||
new PropertyMetadata(false, async (d, e) => await ((FilePreview)d).OnFilePropertyChanged()));
|
||||
|
||||
[ObservableProperty]
|
||||
private ImagePreviewer? previewer;
|
||||
|
||||
public FilePreview()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public File File
|
||||
{
|
||||
get => (File)GetValue(FilesProperty);
|
||||
set => SetValue(FilesProperty, value);
|
||||
}
|
||||
|
||||
public bool IsPreviewLoading(BitmapSource? bitmapSource)
|
||||
{
|
||||
return bitmapSource == null;
|
||||
}
|
||||
|
||||
private async Task OnFilePropertyChanged()
|
||||
{
|
||||
if (File == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Implement plugin pattern to support any file types.
|
||||
if (IsSupportedImage(File.Extension))
|
||||
{
|
||||
Previewer = new ImagePreviewer(File);
|
||||
var size = await Previewer.GetPreviewSizeAsync();
|
||||
PreviewSizeChanged?.Invoke(this, new PreviewSizeChangedArgs(size));
|
||||
await Previewer.LoadPreviewAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
Previewer = null;
|
||||
PreviewSizeChanged?.Invoke(this, new PreviewSizeChangedArgs(new Size(1280, 720)));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Find all supported file types for the image previewer
|
||||
private 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,
|
||||
};
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
// 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.FilePreviewer.Models
|
||||
{
|
||||
using Windows.Foundation;
|
||||
|
||||
public class PreviewSizeChangedArgs
|
||||
{
|
||||
public PreviewSizeChangedArgs(Size windowSizeRequested)
|
||||
{
|
||||
WindowSizeRequested = windowSizeRequested;
|
||||
}
|
||||
|
||||
public Size WindowSizeRequested { get; init; }
|
||||
}
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||
<RootNamespace>Peek.FilePreviewer</RootNamespace>
|
||||
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="FilePreview.xaml" />
|
||||
<None Remove="Previewers\ImagePreviewer\ImagePreviewer.cs~RFfdea838.TMP" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.0.0" />
|
||||
<PackageReference Include="CommunityToolkit.WinUI.UI.Media" Version="7.1.2" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.1.5" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22000.194" />
|
||||
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Peek.Common\Peek.Common.csproj" />
|
||||
<ProjectReference Include="..\WIC\WIC.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Page Update="FilePreview.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -0,0 +1,24 @@
|
||||
// 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.Common
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Peek.Common.Models;
|
||||
|
||||
public static class NativeMethods
|
||||
{
|
||||
[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);
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
// 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.FilePreviewer.Previewers
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Peek.Common;
|
||||
using Peek.Common.Models;
|
||||
|
||||
public static class ThumbnailHelper
|
||||
{
|
||||
// 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 readonly NativeSize HighQualityThumbnailSize = new NativeSize { Width = 720, Height = 720, };
|
||||
public static readonly NativeSize LowQualityThumbnailSize = new NativeSize { Width = 256, Height = 256, };
|
||||
|
||||
private static readonly NativeSize FallBackThumbnailSize = new NativeSize { Width = 96, Height = 96, };
|
||||
private static readonly NativeSize LastFallBackThumbnailSize = new NativeSize { Width = 32, Height = 32, };
|
||||
|
||||
private static readonly List<NativeSize> ThumbnailFallBackSizes = new List<NativeSize>
|
||||
{
|
||||
HighQualityThumbnailSize,
|
||||
LowQualityThumbnailSize,
|
||||
FallBackThumbnailSize,
|
||||
LastFallBackThumbnailSize,
|
||||
};
|
||||
|
||||
// TODO: Add a re-try system if there is no thumbnail of requested size.
|
||||
public static HResult GetThumbnail(string filename, out IntPtr hbitmap, NativeSize thumbnailSize)
|
||||
{
|
||||
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 options = ThumbnailOptions.BiggerSizeOk | ThumbnailOptions.ThumbnailOnly | ThumbnailOptions.ScaleUp;
|
||||
|
||||
HResult hr = ((IShellItemImageFactory)nativeShellItem).GetImage(thumbnailSize, options, out hbitmap);
|
||||
|
||||
// Try to get thumbnail using the fallback sizes order
|
||||
if (hr != HResult.Ok)
|
||||
{
|
||||
var currentThumbnailFallBackIndex = ThumbnailFallBackSizes.IndexOf(thumbnailSize);
|
||||
var nextThumbnailFallBackIndex = currentThumbnailFallBackIndex + 1;
|
||||
if (nextThumbnailFallBackIndex < ThumbnailFallBackSizes.Count - 1)
|
||||
{
|
||||
hr = GetThumbnail(filename, out hbitmap, ThumbnailFallBackSizes[nextThumbnailFallBackIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
Marshal.ReleaseComObject(nativeShellItem);
|
||||
|
||||
return hr;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
// 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.FilePreviewer.Previewers
|
||||
{
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using WIC;
|
||||
|
||||
public static class WICHelper
|
||||
{
|
||||
public static Task<Windows.Foundation.Size> GetImageSize(string filePath)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
// TODO: Find a way to get file metadata without hydrating files. Look into Shell API/Windows Property System, e.g., IPropertyStore
|
||||
IWICImagingFactory factory = (IWICImagingFactory)new WICImagingFactoryClass();
|
||||
var decoder = factory.CreateDecoderFromFilename(filePath, IntPtr.Zero, StreamAccessMode.GENERIC_READ, WICDecodeOptions.WICDecodeMetadataCacheOnLoad);
|
||||
var frame = decoder?.GetFrame(0);
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
// TODO: Respect EXIF data and find correct orientation
|
||||
frame?.GetSize(out width, out height);
|
||||
|
||||
return new Windows.Foundation.Size(width, height);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,169 @@
|
||||
// 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.FilePreviewer.Previewers
|
||||
{
|
||||
using System;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml.Media.Imaging;
|
||||
using Peek.Common;
|
||||
using Windows.Foundation;
|
||||
using File = Peek.Common.Models.File;
|
||||
|
||||
[INotifyPropertyChanged]
|
||||
public partial class ImagePreviewer : IDisposable
|
||||
{
|
||||
[ObservableProperty]
|
||||
private BitmapSource? preview;
|
||||
|
||||
public ImagePreviewer(File file)
|
||||
{
|
||||
File = file;
|
||||
Dispatcher = DispatcherQueue.GetForCurrentThread();
|
||||
}
|
||||
|
||||
private File File { get; }
|
||||
|
||||
private DispatcherQueue Dispatcher { get; }
|
||||
|
||||
private bool IsHighQualityThumbnailLoaded { get; set; }
|
||||
|
||||
private bool IsFullImageLoaded { get; set; }
|
||||
|
||||
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
|
||||
|
||||
private CancellationToken CancellationToken => _cancellationTokenSource.Token;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_cancellationTokenSource.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
public Task<Size> GetPreviewSizeAsync()
|
||||
{
|
||||
return WICHelper.GetImageSize(File.Path);
|
||||
}
|
||||
|
||||
public Task LoadPreviewAsync()
|
||||
{
|
||||
var lowQualityThumbnailTask = LoadLowQualityThumbnailAsync();
|
||||
var highQualityThumbnailTask = LoadHighQualityThumbnailAsync();
|
||||
var fullImageTask = LoadFullQualityImageAsync();
|
||||
|
||||
return Task.WhenAll(lowQualityThumbnailTask, highQualityThumbnailTask, fullImageTask);
|
||||
}
|
||||
|
||||
private Task LoadLowQualityThumbnailAsync()
|
||||
{
|
||||
var thumbnailTCS = new TaskCompletionSource();
|
||||
Dispatcher.TryEnqueue(async () =>
|
||||
{
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsFullImageLoaded && !IsHighQualityThumbnailLoaded)
|
||||
{
|
||||
// TODO: Handle thumbnail errors
|
||||
ThumbnailHelper.GetThumbnail(Path.GetFullPath(File.Path), out IntPtr hbitmap, ThumbnailHelper.LowQualityThumbnailSize);
|
||||
var thumbnailBitmap = await GetBitmapFromHBitmapAsync(hbitmap);
|
||||
Preview = thumbnailBitmap;
|
||||
}
|
||||
|
||||
thumbnailTCS.SetResult();
|
||||
});
|
||||
|
||||
return thumbnailTCS.Task;
|
||||
}
|
||||
|
||||
private Task LoadHighQualityThumbnailAsync()
|
||||
{
|
||||
var thumbnailTCS = new TaskCompletionSource();
|
||||
Dispatcher.TryEnqueue(async () =>
|
||||
{
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsFullImageLoaded)
|
||||
{
|
||||
// TODO: Handle thumbnail errors
|
||||
ThumbnailHelper.GetThumbnail(Path.GetFullPath(File.Path), out IntPtr hbitmap, ThumbnailHelper.HighQualityThumbnailSize);
|
||||
var thumbnailBitmap = await GetBitmapFromHBitmapAsync(hbitmap);
|
||||
IsHighQualityThumbnailLoaded = true;
|
||||
Preview = thumbnailBitmap;
|
||||
}
|
||||
|
||||
thumbnailTCS.SetResult();
|
||||
});
|
||||
|
||||
return thumbnailTCS.Task;
|
||||
}
|
||||
|
||||
private Task LoadFullQualityImageAsync()
|
||||
{
|
||||
var fullImageTCS = new TaskCompletionSource();
|
||||
Dispatcher.TryEnqueue(async () =>
|
||||
{
|
||||
// TODO: Check if this is performant
|
||||
var bitmap = await GetFullBitmapFromPathAsync(File.Path);
|
||||
IsFullImageLoaded = true;
|
||||
|
||||
if (CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
return;
|
||||
}
|
||||
|
||||
Preview = bitmap;
|
||||
fullImageTCS.SetResult();
|
||||
});
|
||||
|
||||
return fullImageTCS.Task;
|
||||
}
|
||||
|
||||
private static async Task<BitmapImage> GetFullBitmapFromPathAsync(string path)
|
||||
{
|
||||
var bitmap = new BitmapImage();
|
||||
using (FileStream stream = System.IO.File.OpenRead(path))
|
||||
{
|
||||
await bitmap.SetSourceAsync(stream.AsRandomAccessStream());
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private static async Task<BitmapSource> GetBitmapFromHBitmapAsync(IntPtr hbitmap)
|
||||
{
|
||||
try
|
||||
{
|
||||
var bitmap = System.Drawing.Image.FromHbitmap(hbitmap);
|
||||
var bitmapImage = new BitmapImage();
|
||||
using (var stream = new MemoryStream())
|
||||
{
|
||||
bitmap.Save(stream, ImageFormat.Bmp);
|
||||
stream.Position = 0;
|
||||
await bitmapImage.SetSourceAsync(stream.AsRandomAccessStream());
|
||||
}
|
||||
|
||||
return bitmapImage;
|
||||
}
|
||||
finally
|
||||
{
|
||||
// delete HBitmap to avoid memory leaks
|
||||
NativeMethods.DeleteObject(hbitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
15
src/modules/peek/Peek.UI.WPF/App.xaml
Normal file
@ -0,0 +1,15 @@
|
||||
<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>
|
94
src/modules/peek/Peek.UI.WPF/App.xaml.cs
Normal file
@ -0,0 +1,94 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
10
src/modules/peek/Peek.UI.WPF/AssemblyInfo.cs
Normal file
@ -0,0 +1,10 @@
|
||||
// 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)
|
||||
]
|
BIN
src/modules/peek/Peek.UI.WPF/Assets/error.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
@ -0,0 +1,21 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
61
src/modules/peek/Peek.UI.WPF/Extensions/SizeExtensions.cs
Normal file
@ -0,0 +1,61 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
41
src/modules/peek/Peek.UI.WPF/Extensions/WindowExtensions.cs
Normal file
@ -0,0 +1,41 @@
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
}
|
34
src/modules/peek/Peek.UI.WPF/Helpers/FileExplorerHelper.cs
Normal file
@ -0,0 +1,34 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
122
src/modules/peek/Peek.UI.WPF/Helpers/FileLoadHelper.cs
Normal file
@ -0,0 +1,122 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
77
src/modules/peek/Peek.UI.WPF/Helpers/FileTypeHelper.cs
Normal file
@ -0,0 +1,77 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
128
src/modules/peek/Peek.UI.WPF/Helpers/ThumbnailHelper.cs
Normal file
@ -0,0 +1,128 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
21
src/modules/peek/Peek.UI.WPF/Models/DimensionData.cs
Normal file
@ -0,0 +1,21 @@
|
||||
// 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; }
|
||||
}
|
||||
}
|
30
src/modules/peek/Peek.UI.WPF/Models/IShellItem.cs
Normal file
@ -0,0 +1,30 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
19
src/modules/peek/Peek.UI.WPF/Models/ObservableObject.cs
Normal file
@ -0,0 +1,19 @@
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
}
|
85
src/modules/peek/Peek.UI.WPF/Models/ObservableRectangle.cs
Normal file
@ -0,0 +1,85 @@
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
88
src/modules/peek/Peek.UI.WPF/Models/ObservableWindowData.cs
Normal file
@ -0,0 +1,88 @@
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
28
src/modules/peek/Peek.UI.WPF/Native/NativeEventWaiter.cs
Normal file
@ -0,0 +1,28 @@
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
54
src/modules/peek/Peek.UI.WPF/Native/NativeMethods.cs
Normal file
@ -0,0 +1,54 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
182
src/modules/peek/Peek.UI.WPF/Native/NativeModels.cs
Normal file
@ -0,0 +1,182 @@
|
||||
// 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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
90
src/modules/peek/Peek.UI.WPF/Peek.UI.WPF.csproj
Normal file
@ -0,0 +1,90 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
|
||||
<AssemblyName>PowerToys.Peek.UI</AssemblyName>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWPF>true</UseWPF>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\modules\Peek\</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>
|
BIN
src/modules/peek/Peek.UI.WPF/Resources/Peek.ico
Normal file
After Width: | Height: | Size: 149 KiB |
19
src/modules/peek/Peek.UI.WPF/Themes/Dark.xaml
Normal file
@ -0,0 +1,19 @@
|
||||
<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>
|
19
src/modules/peek/Peek.UI.WPF/Themes/HighContrast1.xaml
Normal file
@ -0,0 +1,19 @@
|
||||
<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>
|
19
src/modules/peek/Peek.UI.WPF/Themes/HighContrast2.xaml
Normal file
@ -0,0 +1,19 @@
|
||||
<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>
|
19
src/modules/peek/Peek.UI.WPF/Themes/HighContrastBlack.xaml
Normal file
@ -0,0 +1,19 @@
|
||||
<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>
|
19
src/modules/peek/Peek.UI.WPF/Themes/HighContrastWhite.xaml
Normal file
@ -0,0 +1,19 @@
|
||||
<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>
|
19
src/modules/peek/Peek.UI.WPF/Themes/Light.xaml
Normal file
@ -0,0 +1,19 @@
|
||||
<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>
|
301
src/modules/peek/Peek.UI.WPF/ViewModels/MainViewModel.cs
Normal file
@ -0,0 +1,301 @@
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
37
src/modules/peek/Peek.UI.WPF/Views/MainWindow.xaml
Normal file
@ -0,0 +1,37 @@
|
||||
<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>
|
115
src/modules/peek/Peek.UI.WPF/Views/MainWindow.xaml.cs
Normal file
@ -0,0 +1,115 @@
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
18
src/modules/peek/Peek.UI/App.xaml
Normal file
@ -0,0 +1,18 @@
|
||||
<!-- Copyright (c) Microsoft Corporation and Contributors. -->
|
||||
<!-- Licensed under the MIT License. -->
|
||||
|
||||
<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:local="using:Peek.UI">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
<!-- Other merged dictionaries here -->
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
<!-- Other app resources here -->
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
58
src/modules/peek/Peek.UI/App.xaml.cs
Normal file
@ -0,0 +1,58 @@
|
||||
// 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
|
||||
{
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Threading;
|
||||
using ManagedCommon;
|
||||
using Microsoft.UI.Dispatching;
|
||||
using Microsoft.UI.Xaml;
|
||||
using WinUIEx;
|
||||
|
||||
/// <summary>
|
||||
/// Provides application-specific behavior to supplement the default Application class.
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
public static int PowerToysPID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="App"/> class.
|
||||
/// Initializes the singleton application object. This is the first line of authored code
|
||||
/// executed, and as such is the logical equivalent of main() or WinMain().
|
||||
/// </summary>
|
||||
public App()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Invoked when the application is launched.
|
||||
/// </summary>
|
||||
/// <param name="args">Details about the launch request and process.</param>
|
||||
protected override void OnLaunched(LaunchActivatedEventArgs args)
|
||||
{
|
||||
var cmdArgs = Environment.GetCommandLineArgs();
|
||||
if (cmdArgs?.Length > 1)
|
||||
{
|
||||
if (int.TryParse(cmdArgs[cmdArgs.Length - 1], out int powerToysRunnerPid))
|
||||
{
|
||||
RunnerHelper.WaitForPowerToysRunner(powerToysRunnerPid, () =>
|
||||
{
|
||||
Environment.Exit(0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window = new MainWindow();
|
||||
|
||||
window.Activate();
|
||||
window.Hide();
|
||||
}
|
||||
|
||||
private Window? window;
|
||||
}
|
||||
}
|
BIN
src/modules/peek/Peek.UI/Assets/LockScreenLogo.scale-200.png
Normal file
After Width: | Height: | Size: 432 B |
BIN
src/modules/peek/Peek.UI/Assets/Peek.ico
Normal file
After Width: | Height: | Size: 149 KiB |
BIN
src/modules/peek/Peek.UI/Assets/SplashScreen.scale-200.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
src/modules/peek/Peek.UI/Assets/Square150x150Logo.scale-200.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
src/modules/peek/Peek.UI/Assets/Square44x44Logo.scale-200.png
Normal file
After Width: | Height: | Size: 637 B |
After Width: | Height: | Size: 283 B |
BIN
src/modules/peek/Peek.UI/Assets/StoreLogo.png
Normal file
After Width: | Height: | Size: 456 B |
BIN
src/modules/peek/Peek.UI/Assets/Wide310x150Logo.scale-200.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
49
src/modules/peek/Peek.UI/Extensions/SizeExtensions.cs
Normal file
@ -0,0 +1,49 @@
|
||||
// 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.Extensions
|
||||
{
|
||||
using Windows.Foundation;
|
||||
|
||||
public static class SizeExtensions
|
||||
{
|
||||
public static Size Fit(this Size sizeToFit, Size maxSize, Size minSize)
|
||||
{
|
||||
double fittedWidth = sizeToFit.Width;
|
||||
double fittedHeight = sizeToFit.Height;
|
||||
|
||||
double ratioWidth = sizeToFit.Width / maxSize.Width;
|
||||
double ratioHeight = sizeToFit.Height / maxSize.Height;
|
||||
|
||||
if (ratioWidth > ratioHeight)
|
||||
{
|
||||
if (ratioWidth > 1)
|
||||
{
|
||||
fittedWidth = maxSize.Width;
|
||||
fittedHeight = sizeToFit.Height / ratioWidth;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ratioHeight > 1)
|
||||
{
|
||||
fittedWidth = sizeToFit.Width / ratioHeight;
|
||||
fittedHeight = maxSize.Height;
|
||||
}
|
||||
}
|
||||
|
||||
if (fittedWidth < minSize.Width)
|
||||
{
|
||||
fittedWidth = minSize.Width;
|
||||
}
|
||||
|
||||
if (fittedHeight < minSize.Height)
|
||||
{
|
||||
fittedHeight = minSize.Height;
|
||||
}
|
||||
|
||||
return new Size(fittedWidth, fittedHeight);
|
||||
}
|
||||
}
|
||||
}
|
29
src/modules/peek/Peek.UI/Extensions/WindowExtensions.cs
Normal file
@ -0,0 +1,29 @@
|
||||
// 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.Extensions
|
||||
{
|
||||
using System.Drawing;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Windows.Win32;
|
||||
using Windows.Win32.Foundation;
|
||||
using Windows.Win32.Graphics.Gdi;
|
||||
using WinUIEx;
|
||||
|
||||
public static class WindowExtensions
|
||||
{
|
||||
public static Size GetMonitorSize(this Window window)
|
||||
{
|
||||
var hwnd = new HWND(window.GetWindowHandle());
|
||||
var hwndDesktop = PInvoke.MonitorFromWindow(hwnd, MONITOR_FROM_FLAGS.MONITOR_DEFAULTTONEAREST);
|
||||
MONITORINFO info = new ();
|
||||
info.cbSize = 40;
|
||||
PInvoke.GetMonitorInfo(hwndDesktop, ref info);
|
||||
var monitorWidth = info.rcMonitor.left + info.rcMonitor.right;
|
||||
var monitorHeight = info.rcMonitor.bottom + info.rcMonitor.top;
|
||||
|
||||
return new Size(monitorWidth, monitorHeight);
|
||||
}
|
||||
}
|
||||
}
|
37
src/modules/peek/Peek.UI/Helpers/FileExplorerHelper.cs
Normal file
@ -0,0 +1,37 @@
|
||||
// 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;
|
||||
using Peek.Common.Models;
|
||||
using Peek.UI.Native;
|
||||
|
||||
namespace Peek.UI.Helpers
|
||||
{
|
||||
public static class FileExplorerHelper
|
||||
{
|
||||
public static List<File> GetSelectedFileExplorerFiles()
|
||||
{
|
||||
var foregroundWindowHandle = NativeMethods.GetForegroundWindow();
|
||||
|
||||
var selectedItems = new List<File>();
|
||||
var shell = new Shell32.Shell();
|
||||
foreach (SHDocVw.InternetExplorer window in shell.Windows())
|
||||
{
|
||||
if (window.HWND == (int)foregroundWindowHandle)
|
||||
{
|
||||
Shell32.FolderItems items = ((Shell32.IShellFolderViewDual2)window.Document).SelectedItems();
|
||||
if (items != null && items.Count > 0)
|
||||
{
|
||||
foreach (Shell32.FolderItem item in items)
|
||||
{
|
||||
selectedItems.Add(new File(item.Path));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return selectedItems;
|
||||
}
|
||||
}
|
||||
}
|
31
src/modules/peek/Peek.UI/MainWindow.xaml
Normal file
@ -0,0 +1,31 @@
|
||||
<!-- Copyright (c) Microsoft Corporation and Contributors. -->
|
||||
<!-- Licensed under the MIT License. -->
|
||||
|
||||
<winuiex:WindowEx
|
||||
x:Class="Peek.UI.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:fp="using:Peek.FilePreviewer"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:views="using:Peek.UI.Views"
|
||||
xmlns:winuiex="using:WinUIEx"
|
||||
mc:Ignorable="d">
|
||||
<winuiex:WindowEx.Backdrop>
|
||||
<winuiex:MicaSystemBackdrop />
|
||||
</winuiex:WindowEx.Backdrop>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="32" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<views:TitleBar x:Name="TitleBarControl" Grid.Row="0" />
|
||||
|
||||
<fp:FilePreview
|
||||
Grid.Row="1"
|
||||
File="{x:Bind ViewModel.CurrentFile, Mode=OneWay}"
|
||||
PreviewSizeChanged="FilePreviewer_PreviewSizeChanged" />
|
||||
</Grid>
|
||||
</winuiex:WindowEx>
|
98
src/modules/peek/Peek.UI/MainWindow.xaml.cs
Normal file
@ -0,0 +1,98 @@
|
||||
// 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
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using interop;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Peek.Common.Models;
|
||||
using Peek.FilePreviewer.Models;
|
||||
using Peek.UI.Extensions;
|
||||
using Peek.UI.Helpers;
|
||||
using Peek.UI.Native;
|
||||
using Windows.Foundation;
|
||||
using WinUIEx;
|
||||
|
||||
/// <summary>
|
||||
/// An empty window that can be used on its own or navigated to within a Frame.
|
||||
/// </summary>
|
||||
public sealed partial class MainWindow : WindowEx
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
ViewModel = new MainWindowViewModel();
|
||||
|
||||
NativeEventWaiter.WaitForEventLoop(Constants.ShowPeekEvent(), OnPeekHotkey);
|
||||
|
||||
TitleBarControl.SetToWindow(this);
|
||||
|
||||
AppWindow.Closing += AppWindow_Closing;
|
||||
}
|
||||
|
||||
public MainWindowViewModel ViewModel { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Handle Peek hotkey, by toggling the window visibility and querying files when necessary.
|
||||
/// </summary>
|
||||
private void OnPeekHotkey()
|
||||
{
|
||||
if (AppWindow.IsVisible)
|
||||
{
|
||||
this.Hide();
|
||||
ViewModel.Files = new List<File>();
|
||||
ViewModel.CurrentFile = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
var fileExplorerSelectedFiles = FileExplorerHelper.GetSelectedFileExplorerFiles();
|
||||
if (fileExplorerSelectedFiles.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ViewModel.Files = fileExplorerSelectedFiles;
|
||||
ViewModel.CurrentFile = fileExplorerSelectedFiles.First();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle FilePreviewerSizeChanged event to adjust window size and position accordingly.
|
||||
/// </summary>
|
||||
/// <param name="sender">object</param>
|
||||
/// <param name="e">PreviewSizeChangedArgs</param>
|
||||
private void FilePreviewer_PreviewSizeChanged(object sender, PreviewSizeChangedArgs e)
|
||||
{
|
||||
var requestedSize = e.WindowSizeRequested;
|
||||
var monitorSize = this.GetMonitorSize();
|
||||
|
||||
// TODO: Use design-defined rules for adjusted window size
|
||||
var titleBarHeight = TitleBarControl.ActualHeight;
|
||||
var maxContentSize = new Size(monitorSize.Width * 0.8, (monitorSize.Height - titleBarHeight) * 0.8);
|
||||
var minContentSize = new Size(500, 500 - titleBarHeight);
|
||||
|
||||
var adjustedContentSize = requestedSize.Fit(maxContentSize, minContentSize);
|
||||
|
||||
// TODO: Only re-center if window has not been resized by user (or use design-defined logic).
|
||||
// TODO: Investigate why portrait images do not perfectly fit edge-to-edge
|
||||
this.CenterOnScreen(adjustedContentSize.Width, adjustedContentSize.Height + titleBarHeight);
|
||||
this.Show();
|
||||
this.BringToFront();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handle AppWindow closing to prevent app termination on close.
|
||||
/// </summary>
|
||||
/// <param name="sender">AppWindow</param>
|
||||
/// <param name="args">AppWindowClosingEventArgs</param>
|
||||
private void AppWindow_Closing(AppWindow sender, AppWindowClosingEventArgs args)
|
||||
{
|
||||
args.Cancel = true;
|
||||
this.Hide();
|
||||
}
|
||||
}
|
||||
}
|
19
src/modules/peek/Peek.UI/MainWindowViewModel.cs
Normal file
@ -0,0 +1,19 @@
|
||||
// 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
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Peek.Common.Models;
|
||||
|
||||
public partial class MainWindowViewModel : ObservableObject
|
||||
{
|
||||
[ObservableProperty]
|
||||
private File? currentFile;
|
||||
|
||||
[ObservableProperty]
|
||||
private List<File> files = new ();
|
||||
}
|
||||
}
|
15
src/modules/peek/Peek.UI/Native/NativeMethods.cs
Normal file
@ -0,0 +1,15 @@
|
||||
// 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.Native
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public static class NativeMethods
|
||||
{
|
||||
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
|
||||
internal static extern IntPtr GetForegroundWindow();
|
||||
}
|
||||
}
|
29
src/modules/peek/Peek.UI/NativeEventWaiter.cs
Normal file
@ -0,0 +1,29 @@
|
||||
// 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 Microsoft.UI.Dispatching;
|
||||
|
||||
namespace Peek.UI.Native
|
||||
{
|
||||
public static class NativeEventWaiter
|
||||
{
|
||||
public static void WaitForEventLoop(string eventName, Action callback)
|
||||
{
|
||||
var dispatcherQueue = DispatcherQueue.GetForCurrentThread();
|
||||
new Thread(() =>
|
||||
{
|
||||
var eventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, eventName);
|
||||
while (true)
|
||||
{
|
||||
if (eventHandle.WaitOne())
|
||||
{
|
||||
dispatcherQueue.TryEnqueue(() => callback());
|
||||
}
|
||||
}
|
||||
}).Start();
|
||||
}
|
||||
}
|
||||
}
|
2
src/modules/peek/Peek.UI/NativeMethods.txt
Normal file
@ -0,0 +1,2 @@
|
||||
MonitorFromWindow
|
||||
GetMonitorInfo
|
48
src/modules/peek/Peek.UI/Package.appxmanifest
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<Package
|
||||
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
|
||||
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
|
||||
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
|
||||
IgnorableNamespaces="uap rescap">
|
||||
|
||||
<Identity
|
||||
Name="62c2f436-8802-4c26-a73d-b3b8613016fd"
|
||||
Publisher="CN=sachaple"
|
||||
Version="1.0.0.0" />
|
||||
|
||||
<Properties>
|
||||
<DisplayName>Peek.UI</DisplayName>
|
||||
<PublisherDisplayName>sachaple</PublisherDisplayName>
|
||||
<Logo>Assets\StoreLogo.png</Logo>
|
||||
</Properties>
|
||||
|
||||
<Dependencies>
|
||||
<TargetDeviceFamily Name="Windows.Universal" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.17763.0" MaxVersionTested="10.0.19041.0" />
|
||||
</Dependencies>
|
||||
|
||||
<Resources>
|
||||
<Resource Language="x-generate"/>
|
||||
</Resources>
|
||||
|
||||
<Applications>
|
||||
<Application Id="App"
|
||||
Executable="$targetnametoken$.exe"
|
||||
EntryPoint="$targetentrypoint$">
|
||||
<uap:VisualElements
|
||||
DisplayName="Peek.UI"
|
||||
Description="Peek.UI"
|
||||
BackgroundColor="transparent"
|
||||
Square150x150Logo="Assets\Square150x150Logo.png"
|
||||
Square44x44Logo="Assets\Square44x44Logo.png">
|
||||
<uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png" />
|
||||
<uap:SplashScreen Image="Assets\SplashScreen.png" />
|
||||
</uap:VisualElements>
|
||||
</Application>
|
||||
</Applications>
|
||||
|
||||
<Capabilities>
|
||||
<rescap:Capability Name="runFullTrust" />
|
||||
</Capabilities>
|
||||
</Package>
|
97
src/modules/peek/Peek.UI/Peek.UI.csproj
Normal file
@ -0,0 +1,97 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<AssemblyName>PowerToys.Peek.UI</AssemblyName>
|
||||
<AssemblyTitle>PowerToys.Peek.UI</AssemblyTitle>
|
||||
<AssemblyDescription>PowerToys Peek UI</AssemblyDescription>
|
||||
<RootNamespace>Peek.UI</RootNamespace>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net7.0-windows10.0.19041.0</TargetFramework>
|
||||
<TargetPlatformMinVersion>10.0.19041.0</TargetPlatformMinVersion>
|
||||
<OutputPath>..\..\..\..\$(Platform)\$(Configuration)\modules\Peek\</OutputPath>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
<Platforms>x86;x64;ARM64</Platforms>
|
||||
<RuntimeIdentifiers>win10-x86;win10-x64;win10-arm64</RuntimeIdentifiers>
|
||||
<UseWinUI>true</UseWinUI>
|
||||
<EnableMsixTooling>true</EnableMsixTooling>
|
||||
<GenerateSatelliteAssembliesForCore>true</GenerateSatelliteAssembliesForCore>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
<AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath>
|
||||
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
|
||||
<WindowsPackageType>None</WindowsPackageType>
|
||||
<WindowsAppSDKSelfContained>true</WindowsAppSDKSelfContained>
|
||||
<SupportedOSPlatformVersion>10.0.19041.0</SupportedOSPlatformVersion>
|
||||
<Nullable>Enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Content Remove="Assets\Peek.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\Peek.ico" />
|
||||
<None Remove="Views\TitleBar.xaml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<COMReference Include="Shell32">
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<Guid>50a7e9b0-70ef-11d1-b75a-00a0c90564fe</Guid>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>false</Isolated>
|
||||
<EmbedInteropTypes>true</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
<COMReference Include="SHDocVw">
|
||||
<VersionMinor>1</VersionMinor>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<Guid>eab22ac0-30c1-11cf-a7eb-0000c05bae0b</Guid>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>false</Isolated>
|
||||
<EmbedInteropTypes>true</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\SplashScreen.scale-200.png" />
|
||||
<Content Include="Assets\LockScreenLogo.scale-200.png" />
|
||||
<Content Include="Assets\Square150x150Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.scale-200.png" />
|
||||
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
|
||||
<Content Include="Assets\StoreLogo.png" />
|
||||
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Windows.CsWin32" Version="0.2.46-beta">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.1.5" />
|
||||
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.22000.194" />
|
||||
<PackageReference Include="WinUIEx" Version="1.8.0" />
|
||||
<Manifest Include="$(ApplicationManifest)" />
|
||||
</ItemGroup>
|
||||
|
||||
<!--
|
||||
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
|
||||
Tools extension to be activated for this project even if the Windows App SDK Nuget
|
||||
package has not yet been restored.
|
||||
-->
|
||||
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
|
||||
<ProjectCapability Include="Msix" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\interop\PowerToys.Interop.vcxproj" />
|
||||
<ProjectReference Include="..\..\..\common\ManagedCommon\ManagedCommon.csproj" />
|
||||
<ProjectReference Include="..\Peek.Common\Peek.Common.csproj" />
|
||||
<ProjectReference Include="..\Peek.FilePreviewer\Peek.FilePreviewer.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Assets\Peek.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Views\TitleBar.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
</Project>
|
126
src/modules/peek/Peek.UI/Strings/en-us/Resources.resw
Normal file
@ -0,0 +1,126 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="AppTitle.Title" xml:space="preserve">
|
||||
<value>Peek</value>
|
||||
</data>
|
||||
<data name="AppTitleText.Text" xml:space="preserve">
|
||||
<value>Peek</value>
|
||||
</data>
|
||||
</root>
|
25
src/modules/peek/Peek.UI/Views/TitleBar.xaml
Normal file
@ -0,0 +1,25 @@
|
||||
<!-- Copyright (c) Microsoft Corporation and Contributors. -->
|
||||
<!-- Licensed under the MIT License. -->
|
||||
|
||||
<UserControl
|
||||
x:Class="Peek.UI.Views.TitleBar"
|
||||
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:local="using:Peek.UI.Views"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d">
|
||||
|
||||
<Grid x:Name="titleBar">
|
||||
<StackPanel
|
||||
Margin="16,8,8,8"
|
||||
VerticalAlignment="Top"
|
||||
Orientation="Horizontal">
|
||||
<Image Source="../Assets/Square44x44Logo.png" />
|
||||
<TextBlock
|
||||
x:Uid="AppTitleText"
|
||||
Margin="12,0,0,0"
|
||||
Style="{StaticResource CaptionTextBlockStyle}" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
44
src/modules/peek/Peek.UI/Views/TitleBar.xaml.cs
Normal file
@ -0,0 +1,44 @@
|
||||
// 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.Views
|
||||
{
|
||||
using System;
|
||||
using ManagedCommon;
|
||||
using Microsoft.UI;
|
||||
using Microsoft.UI.Windowing;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using WinUIEx;
|
||||
using MUX = Microsoft.UI.Xaml;
|
||||
|
||||
public sealed partial class TitleBar : UserControl
|
||||
{
|
||||
public TitleBar()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public void SetToWindow(MainWindow mainWindow)
|
||||
{
|
||||
if (AppWindowTitleBar.IsCustomizationSupported())
|
||||
{
|
||||
AppWindow window = mainWindow.GetAppWindow();
|
||||
window.TitleBar.ExtendsContentIntoTitleBar = true;
|
||||
window.TitleBar.ButtonBackgroundColor = Colors.Transparent;
|
||||
mainWindow.SetTitleBar(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
var hWnd = WinRT.Interop.WindowNative.GetWindowHandle(this);
|
||||
ThemeHelpers.SetImmersiveDarkMode(hWnd, ThemeHelpers.GetAppTheme() == AppTheme.Dark);
|
||||
Visibility = MUX.Visibility.Collapsed;
|
||||
|
||||
// Set window icon
|
||||
WindowId windowId = Win32Interop.GetWindowIdFromWindow(hWnd);
|
||||
AppWindow appWindow = AppWindow.GetFromWindowId(windowId);
|
||||
appWindow.SetIcon("Assets/Peek.ico");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
25
src/modules/peek/Peek.UI/app.manifest
Normal file
@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="Peek.UI.app"/>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!--The ID below informs the system that this application is compatible with OS features first introduced in Windows 8.
|
||||
For more info see https://docs.microsoft.com/windows/win32/sysinfo/targeting-your-application-at-windows-8-1
|
||||
|
||||
It is also necessary to support features in unpackaged applications, for example the custom titlebar implementation.-->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<!-- The combination of below two tags have the following effect:
|
||||
1) Per-Monitor for >= Windows 10 Anniversary Update
|
||||
2) System < Windows 10 Anniversary Update
|
||||
-->
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/PM</dpiAware>
|
||||
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2, PerMonitor</dpiAwareness>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
</assembly>
|
7
src/modules/peek/WIC/Classes/CLSID.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace WIC
|
||||
{
|
||||
internal static class CLSID
|
||||
{
|
||||
public const string WICImagingFactory = "cacaf262-9370-4615-a13b-9f5539da4c0a";
|
||||
}
|
||||
}
|
14
src/modules/peek/WIC/Classes/WICImagingFactory.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
[ComImport]
|
||||
[Guid(IID.IWICImagingFactory)]
|
||||
[CoClass(typeof(WICImagingFactoryClass))]
|
||||
public interface WICImagingFactory : IWICImagingFactory { }
|
||||
|
||||
[ComImport]
|
||||
[Guid(CLSID.WICImagingFactory)]
|
||||
[ComDefaultInterface(typeof(IWICImagingFactory))]
|
||||
public class WICImagingFactoryClass { }
|
||||
}
|
43
src/modules/peek/WIC/CoTaskMemPtr.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
internal struct CoTaskMemPtr : IDisposable
|
||||
{
|
||||
public static CoTaskMemPtr From<T>(T? nullableStructure) where T : struct
|
||||
{
|
||||
IntPtr value;
|
||||
if (nullableStructure.HasValue)
|
||||
{
|
||||
value = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(T)));
|
||||
Marshal.StructureToPtr(nullableStructure, value, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = IntPtr.Zero;
|
||||
}
|
||||
return new CoTaskMemPtr(value);
|
||||
}
|
||||
|
||||
public CoTaskMemPtr(IntPtr value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private IntPtr value;
|
||||
|
||||
public static implicit operator IntPtr(CoTaskMemPtr safeIntPtr)
|
||||
{
|
||||
return safeIntPtr.value;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (value != IntPtr.Zero)
|
||||
{
|
||||
Marshal.FreeCoTaskMem(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
16
src/modules/peek/WIC/Constants/ContainerFormat.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
public static class ContainerFormat
|
||||
{
|
||||
public static readonly Guid Bmp = new Guid(0x0af1d87e, 0xfcfe, 0x4188, 0xbd, 0xeb, 0xa7, 0x90, 0x64, 0x71, 0xcb, 0xe3);
|
||||
public static readonly Guid Png = new Guid(0x1b7cfaf4, 0x713f, 0x473c, 0xbb, 0xcd, 0x61, 0x37, 0x42, 0x5f, 0xae, 0xaf);
|
||||
public static readonly Guid Ico = new Guid(0xa3a860c4, 0x338f, 0x4c17, 0x91, 0x9a, 0xfb, 0xa4, 0xb5, 0x62, 0x8f, 0x21);
|
||||
public static readonly Guid Jpeg = new Guid(0x19e4a5aa, 0x5662, 0x4fc5, 0xa0, 0xc0, 0x17, 0x58, 0x02, 0x8e, 0x10, 0x57);
|
||||
public static readonly Guid Tiff = new Guid(0x163bcc30, 0xe2e9, 0x4f0b, 0x96, 0x1d, 0xa3, 0xe9, 0xfd, 0xb7, 0x88, 0xa3);
|
||||
public static readonly Guid Gif = new Guid(0x1f8a5601, 0x7d4d, 0x4cbd, 0x9c, 0x82, 0x1b, 0xc8, 0xd4, 0xee, 0xb9, 0xa5);
|
||||
public static readonly Guid Wmp = new Guid(0x57a37caa, 0x367a, 0x4540, 0x91, 0x6b, 0xf1, 0x83, 0xc5, 0x09, 0x3a, 0x4b);
|
||||
public static readonly Guid Dds = new Guid(0x9967cb95, 0x2e85, 0x4ac8, 0x8c, 0xa2, 0x83, 0xd7, 0xcc, 0xd4, 0x25, 0xc9);
|
||||
}
|
||||
}
|
7
src/modules/peek/WIC/Constants/HResult.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace WIC
|
||||
{
|
||||
public struct HResult
|
||||
{
|
||||
public const int WINCODEC_ERR_PROPERTYNOTFOUND = unchecked((int)0x88982F40);
|
||||
}
|
||||
}
|
10
src/modules/peek/WIC/Constants/Vendor.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
public static class Vendor
|
||||
{
|
||||
public static readonly Guid Microsoft = new Guid(0xf0e749ca, 0xedef, 0x4589, 0xa7, 0x3a, 0xee, 0xe, 0x62, 0x6a, 0x2a, 0x2b);
|
||||
public static readonly Guid MicrosoftBuiltIn = new Guid(0x257a30fd, 0x6b6, 0x462b, 0xae, 0xa4, 0x63, 0xf7, 0xb, 0x86, 0xe5, 0x33);
|
||||
}
|
||||
}
|
98
src/modules/peek/WIC/Constants/WICPixelFormat.cs
Normal file
@ -0,0 +1,98 @@
|
||||
using System;
|
||||
|
||||
namespace WIC.Constants
|
||||
{
|
||||
public static class WICPixelFormat
|
||||
{
|
||||
public static readonly Guid WICPixelFormatDontCare = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x00);
|
||||
public static readonly Guid WICPixelFormat1bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x01);
|
||||
public static readonly Guid WICPixelFormat2bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x02);
|
||||
public static readonly Guid WICPixelFormat4bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x03);
|
||||
public static readonly Guid WICPixelFormat8bppIndexed = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x04);
|
||||
public static readonly Guid WICPixelFormatBlackWhite = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x05);
|
||||
public static readonly Guid WICPixelFormat2bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x06);
|
||||
public static readonly Guid WICPixelFormat4bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x07);
|
||||
public static readonly Guid WICPixelFormat8bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x08);
|
||||
public static readonly Guid WICPixelFormat8bppAlpha = new Guid(0xe6cd0116, 0xeeba, 0x4161, 0xaa, 0x85, 0x27, 0xdd, 0x9f, 0xb3, 0xa8, 0x95);
|
||||
public static readonly Guid WICPixelFormat16bppBGR555 = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x09);
|
||||
public static readonly Guid WICPixelFormat16bppBGR565 = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0a);
|
||||
public static readonly Guid WICPixelFormat16bppBGRA5551 = new Guid(0x05ec7c2b, 0xf1e6, 0x4961, 0xad, 0x46, 0xe1, 0xcc, 0x81, 0x0a, 0x87, 0xd2);
|
||||
public static readonly Guid WICPixelFormat16bppGray = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0b);
|
||||
public static readonly Guid WICPixelFormat24bppBGR = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0c);
|
||||
public static readonly Guid WICPixelFormat24bppRGB = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0d);
|
||||
public static readonly Guid WICPixelFormat32bppBGR = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0e);
|
||||
public static readonly Guid WICPixelFormat32bppBGRA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x0f);
|
||||
public static readonly Guid WICPixelFormat32bppPBGRA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x10);
|
||||
public static readonly Guid WICPixelFormat32bppGrayFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x11);
|
||||
public static readonly Guid WICPixelFormat32bppRGB = new Guid(0xd98c6b95, 0x3efe, 0x47d6, 0xbb, 0x25, 0xeb, 0x17, 0x48, 0xab, 0x0c, 0xf1);
|
||||
public static readonly Guid WICPixelFormat32bppRGBA = new Guid(0xf5c7ad2d, 0x6a8d, 0x43dd, 0xa7, 0xa8, 0xa2, 0x99, 0x35, 0x26, 0x1a, 0xe9);
|
||||
public static readonly Guid WICPixelFormat32bppPRGBA = new Guid(0x3cc4a650, 0xa527, 0x4d37, 0xa9, 0x16, 0x31, 0x42, 0xc7, 0xeb, 0xed, 0xba);
|
||||
public static readonly Guid WICPixelFormat48bppRGB = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x15);
|
||||
public static readonly Guid WICPixelFormat48bppBGR = new Guid(0xe605a384, 0xb468, 0x46ce, 0xbb, 0x2e, 0x36, 0xf1, 0x80, 0xe6, 0x43, 0x13);
|
||||
public static readonly Guid WICPixelFormat64bppRGB = new Guid(0xa1182111, 0x186d, 0x4d42, 0xbc, 0x6a, 0x9c, 0x83, 0x03, 0xa8, 0xdf, 0xf9);
|
||||
public static readonly Guid WICPixelFormat64bppRGBA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x16);
|
||||
public static readonly Guid WICPixelFormat64bppBGRA = new Guid(0x1562ff7c, 0xd352, 0x46f9, 0x97, 0x9e, 0x42, 0x97, 0x6b, 0x79, 0x22, 0x46);
|
||||
public static readonly Guid WICPixelFormat64bppPRGBA = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x17);
|
||||
public static readonly Guid WICPixelFormat64bppPBGRA = new Guid(0x8c518e8e, 0xa4ec, 0x468b, 0xae, 0x70, 0xc9, 0xa3, 0x5a, 0x9c, 0x55, 0x30);
|
||||
public static readonly Guid WICPixelFormat16bppGrayFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x13);
|
||||
public static readonly Guid WICPixelFormat32bppBGR101010 = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x14);
|
||||
public static readonly Guid WICPixelFormat48bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x12);
|
||||
public static readonly Guid WICPixelFormat48bppBGRFixedPoint = new Guid(0x49ca140e, 0xcab6, 0x493b, 0x9d, 0xdf, 0x60, 0x18, 0x7c, 0x37, 0x53, 0x2a);
|
||||
public static readonly Guid WICPixelFormat96bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x18);
|
||||
public static readonly Guid WICPixelFormat96bppRGBFloat = new Guid(0xe3fed78f, 0xe8db, 0x4acf, 0x84, 0xc1, 0xe9, 0x7f, 0x61, 0x36, 0xb3, 0x27);
|
||||
public static readonly Guid WICPixelFormat128bppRGBAFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x19);
|
||||
public static readonly Guid WICPixelFormat128bppPRGBAFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1a);
|
||||
public static readonly Guid WICPixelFormat128bppRGBFloat = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1b);
|
||||
public static readonly Guid WICPixelFormat32bppCMYK = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1c);
|
||||
public static readonly Guid WICPixelFormat64bppRGBAFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1d);
|
||||
public static readonly Guid WICPixelFormat64bppBGRAFixedPoint = new Guid(0x356de33c, 0x54d2, 0x4a23, 0xbb, 0x4, 0x9b, 0x7b, 0xf9, 0xb1, 0xd4, 0x2d);
|
||||
public static readonly Guid WICPixelFormat64bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x40);
|
||||
public static readonly Guid WICPixelFormat128bppRGBAFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1e);
|
||||
public static readonly Guid WICPixelFormat128bppRGBFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x41);
|
||||
public static readonly Guid WICPixelFormat64bppRGBAHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3a);
|
||||
public static readonly Guid WICPixelFormat64bppPRGBAHalf = new Guid(0x58ad26c2, 0xc623, 0x4d9d, 0xb3, 0x20, 0x38, 0x7e, 0x49, 0xf8, 0xc4, 0x42);
|
||||
public static readonly Guid WICPixelFormat64bppRGBHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x42);
|
||||
public static readonly Guid WICPixelFormat48bppRGBHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3b);
|
||||
public static readonly Guid WICPixelFormat32bppRGBE = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3d);
|
||||
public static readonly Guid WICPixelFormat16bppGrayHalf = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3e);
|
||||
public static readonly Guid WICPixelFormat32bppGrayFixedPoint = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x3f);
|
||||
public static readonly Guid WICPixelFormat32bppRGBA1010102 = new Guid(0x25238D72, 0xFCF9, 0x4522, 0xb5, 0x14, 0x55, 0x78, 0xe5, 0xad, 0x55, 0xe0);
|
||||
public static readonly Guid WICPixelFormat32bppRGBA1010102XR = new Guid(0x00DE6B9A, 0xC101, 0x434b, 0xb5, 0x02, 0xd0, 0x16, 0x5e, 0xe1, 0x12, 0x2c);
|
||||
public static readonly Guid WICPixelFormat32bppR10G10B10A2 = new Guid(0x604e1bb5, 0x8a3c, 0x4b65, 0xb1, 0x1c, 0xbc, 0x0b, 0x8d, 0xd7, 0x5b, 0x7f);
|
||||
public static readonly Guid WICPixelFormat32bppR10G10B10A2HDR10 = new Guid(0x9c215c5d, 0x1acc, 0x4f0e, 0xa4, 0xbc, 0x70, 0xfb, 0x3a, 0xe8, 0xfd, 0x28);
|
||||
public static readonly Guid WICPixelFormat64bppCMYK = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x1f);
|
||||
public static readonly Guid WICPixelFormat24bpp3Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x20);
|
||||
public static readonly Guid WICPixelFormat32bpp4Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x21);
|
||||
public static readonly Guid WICPixelFormat40bpp5Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x22);
|
||||
public static readonly Guid WICPixelFormat48bpp6Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x23);
|
||||
public static readonly Guid WICPixelFormat56bpp7Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x24);
|
||||
public static readonly Guid WICPixelFormat64bpp8Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x25);
|
||||
public static readonly Guid WICPixelFormat48bpp3Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x26);
|
||||
public static readonly Guid WICPixelFormat64bpp4Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x27);
|
||||
public static readonly Guid WICPixelFormat80bpp5Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x28);
|
||||
public static readonly Guid WICPixelFormat96bpp6Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x29);
|
||||
public static readonly Guid WICPixelFormat112bpp7Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2a);
|
||||
public static readonly Guid WICPixelFormat128bpp8Channels = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2b);
|
||||
public static readonly Guid WICPixelFormat40bppCMYKAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2c);
|
||||
public static readonly Guid WICPixelFormat80bppCMYKAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2d);
|
||||
public static readonly Guid WICPixelFormat32bpp3ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2e);
|
||||
public static readonly Guid WICPixelFormat40bpp4ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x2f);
|
||||
public static readonly Guid WICPixelFormat48bpp5ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x30);
|
||||
public static readonly Guid WICPixelFormat56bpp6ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x31);
|
||||
public static readonly Guid WICPixelFormat64bpp7ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x32);
|
||||
public static readonly Guid WICPixelFormat72bpp8ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x33);
|
||||
public static readonly Guid WICPixelFormat64bpp3ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x34);
|
||||
public static readonly Guid WICPixelFormat80bpp4ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x35);
|
||||
public static readonly Guid WICPixelFormat96bpp5ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x36);
|
||||
public static readonly Guid WICPixelFormat112bpp6ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x37);
|
||||
public static readonly Guid WICPixelFormat128bpp7ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x38);
|
||||
public static readonly Guid WICPixelFormat144bpp8ChannelsAlpha = new Guid(0x6fddc324, 0x4e03, 0x4bfe, 0xb1, 0x85, 0x3d, 0x77, 0x76, 0x8d, 0xc9, 0x39);
|
||||
public static readonly Guid WICPixelFormat8bppY = new Guid(0x91B4DB54, 0x2DF9, 0x42F0, 0xB4, 0x49, 0x29, 0x09, 0xBB, 0x3D, 0xF8, 0x8E);
|
||||
public static readonly Guid WICPixelFormat8bppCb = new Guid(0x1339F224, 0x6BFE, 0x4C3E, 0x93, 0x02, 0xE4, 0xF3, 0xA6, 0xD0, 0xCA, 0x2A);
|
||||
public static readonly Guid WICPixelFormat8bppCr = new Guid(0xB8145053, 0x2116, 0x49F0, 0x88, 0x35, 0xED, 0x84, 0x4B, 0x20, 0x5C, 0x51);
|
||||
public static readonly Guid WICPixelFormat16bppCbCr = new Guid(0xFF95BA6E, 0x11E0, 0x4263, 0xBB, 0x45, 0x01, 0x72, 0x1F, 0x34, 0x60, 0xA4);
|
||||
public static readonly Guid WICPixelFormat16bppYQuantizedDctCoefficients = new Guid(0xA355F433, 0x48E8, 0x4A42, 0x84, 0xD8, 0xE2, 0xAA, 0x26, 0xCA, 0x80, 0xA4);
|
||||
public static readonly Guid WICPixelFormat16bppCbQuantizedDctCoefficients = new Guid(0xD2C4FF61, 0x56A5, 0x49C2, 0x8B, 0x5C, 0x4C, 0x19, 0x25, 0x96, 0x48, 0x37);
|
||||
public static readonly Guid WICPixelFormat16bppCrQuantizedDctCoefficients = new Guid(0x2FE354F0, 0x1680, 0x42D8, 0x92, 0x31, 0xE7, 0x3C, 0x05, 0x65, 0xBF, 0xC1);
|
||||
}
|
||||
}
|
8
src/modules/peek/WIC/Enumerations/ExifColorSpace.cs
Normal file
@ -0,0 +1,8 @@
|
||||
namespace WIC
|
||||
{
|
||||
public enum ExifColorSpace : int
|
||||
{
|
||||
SRGB = 1,
|
||||
AdobeSRGB = 2,
|
||||
}
|
||||
}
|
14
src/modules/peek/WIC/Enumerations/LOCKTYPE.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
[Flags]
|
||||
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||
public enum LOCKTYPE : int
|
||||
{
|
||||
LOCK_WRITE = 1,
|
||||
LOCK_EXCLUSIVE = 2,
|
||||
LOCK_ONLYONCE = 4,
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
using System;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
[Flags]
|
||||
public enum MetadataCreationAndPersistOptions : int
|
||||
{
|
||||
WICMetadataCreationDefault = 0x00000000,
|
||||
WICMetadataCreationAllowUnknown = WICMetadataCreationDefault,
|
||||
WICMetadataCreationFailUnknown = 0x00010000,
|
||||
|
||||
WICPersistOptionDefault = 0x00000000,
|
||||
WICPersistOptionLittleEndian = 0x00000000,
|
||||
WICPersistOptionBigEndian = 0x00000001,
|
||||
WICPersistOptionStrictFormat = 0x00000002,
|
||||
WICPersistOptionNoCacheStream = 0x00000004,
|
||||
WICPersistOptionPreferUTF8 = 0x00000008,
|
||||
}
|
||||
}
|
12
src/modules/peek/WIC/Enumerations/STATFLAG.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||
public enum STATFLAG : int
|
||||
{
|
||||
STATFLAG_DEFAULT = 0,
|
||||
STATFLAG_NONAME = 1,
|
||||
STATFLAG_NOOPEN = 2,
|
||||
}
|
||||
}
|
16
src/modules/peek/WIC/Enumerations/STGC.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
[Flags]
|
||||
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||
public enum STGC : int
|
||||
{
|
||||
STGC_DEFAULT = 0,
|
||||
STGC_OVERWRITE = 1,
|
||||
STGC_ONLYIFCURRENT = 2,
|
||||
STGC_DANGEROUSLYCOMMITMERELYTODISKCACHE = 4,
|
||||
STGC_CONSOLIDATE = 8,
|
||||
}
|
||||
}
|
15
src/modules/peek/WIC/Enumerations/STGM.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
[Flags]
|
||||
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||
public enum STGM : int
|
||||
{
|
||||
STGM_READ = 0x00000000,
|
||||
STGM_WRITE = 0x00000001,
|
||||
STGM_READWRITE = 0x00000002,
|
||||
#warning `STGM`: Enumeration incomplete. Consider adding all values.
|
||||
}
|
||||
}
|
13
src/modules/peek/WIC/Enumerations/STGTY.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||
public enum STGTY : int
|
||||
{
|
||||
STGTY_STORAGE = 1,
|
||||
STGTY_STREAM = 2,
|
||||
STGTY_LOCKBYTES = 3,
|
||||
STGTY_PROPERTY = 4,
|
||||
}
|
||||
}
|
12
src/modules/peek/WIC/Enumerations/STREAM_SEEK.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
[EditorBrowsable(EditorBrowsableState.Advanced)]
|
||||
public enum STREAM_SEEK : int
|
||||
{
|
||||
STREAM_SEEK_SET = 0,
|
||||
STREAM_SEEK_CUR = 1,
|
||||
STREAM_SEEK_END = 2,
|
||||
}
|
||||
}
|
11
src/modules/peek/WIC/Enumerations/StreamAccessMode.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
[Flags]
|
||||
public enum StreamAccessMode : int
|
||||
{
|
||||
GENERIC_WRITE = 0x40000000,
|
||||
GENERIC_READ = unchecked((int)0x80000000U),
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
namespace WIC
|
||||
{
|
||||
public enum WICBitmapAlphaChannelOption : int
|
||||
{
|
||||
WICBitmapUseAlpha = 0x00000000,
|
||||
WICBitmapUsePremultipliedAlpha = 0x00000001,
|
||||
WICBitmapIgnoreAlpha = 0x00000002,
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
namespace WIC
|
||||
{
|
||||
public enum WICBitmapCreateCacheOption : int
|
||||
{
|
||||
WICBitmapNoCache = 0x00000000,
|
||||
WICBitmapCacheOnDemand = 0x00000001,
|
||||
WICBitmapCacheOnLoad = 0x00000002,
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
[Flags]
|
||||
public enum WICBitmapDecoderCapabilities : int
|
||||
{
|
||||
WICBitmapDecoderCapabilitySameEncoder = 0x00000001,
|
||||
WICBitmapDecoderCapabilityCanDecodeAllImages = 0x00000002,
|
||||
WICBitmapDecoderCapabilityCanDecodeSomeImages = 0x00000004,
|
||||
WICBitmapDecoderCapabilityCanEnumerateMetadata = 0x00000008,
|
||||
WICBitmapDecoderCapabilityCanDecodeThumbnail = 0x00000010,
|
||||
}
|
||||
}
|
19
src/modules/peek/WIC/Enumerations/WICBitmapDitherType.cs
Normal file
@ -0,0 +1,19 @@
|
||||
namespace WIC
|
||||
{
|
||||
public enum WICBitmapDitherType : int
|
||||
{
|
||||
WICBitmapDitherTypeNone = 0x00000000,
|
||||
WICBitmapDitherTypeSolid = 0x00000000,
|
||||
|
||||
WICBitmapDitherTypeOrdered4x4 = 0x00000001,
|
||||
|
||||
WICBitmapDitherTypeOrdered8x8 = 0x00000002,
|
||||
WICBitmapDitherTypeOrdered16x16 = 0x00000003,
|
||||
WICBitmapDitherTypeSpiral4x4 = 0x00000004,
|
||||
WICBitmapDitherTypeSpiral8x8 = 0x00000005,
|
||||
WICBitmapDitherTypeDualSpiral4x4 = 0x00000006,
|
||||
WICBitmapDitherTypeDualSpiral8x8 = 0x00000007,
|
||||
|
||||
WICBitmapDitherTypeErrorDiffusion = 0x00000008,
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
namespace WIC
|
||||
{
|
||||
public enum WICBitmapEncoderCacheOption : int
|
||||
{
|
||||
WICBitmapEncoderCacheInMemory = 0x00000000,
|
||||
WICBitmapEncoderCacheTempFile = 0x00000001,
|
||||
WICBitmapEncoderNoCache = 0x00000002,
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
namespace WIC
|
||||
{
|
||||
public enum WICBitmapInterpolationMode : int
|
||||
{
|
||||
WICBitmapInterpolationModeNearestNeighbor = 0x00000000,
|
||||
WICBitmapInterpolationModeLinear = 0x00000001,
|
||||
WICBitmapInterpolationModeCubic = 0x00000002,
|
||||
WICBitmapInterpolationModeFant = 0x00000003,
|
||||
/// <remarks>
|
||||
/// Supported beginning with Windows 10.
|
||||
/// </remarks>
|
||||
WICBitmapInterpolationModeHighQualityCubic = 0x00000004,
|
||||
}
|
||||
}
|
11
src/modules/peek/WIC/Enumerations/WICBitmapLockFlags.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using System;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
[Flags]
|
||||
public enum WICBitmapLockFlags : int
|
||||
{
|
||||
WICBitmapLockRead = 0x00000001,
|
||||
WICBitmapLockWrite = 0x00000002,
|
||||
}
|
||||
}
|
20
src/modules/peek/WIC/Enumerations/WICBitmapPaletteType.cs
Normal file
@ -0,0 +1,20 @@
|
||||
namespace WIC
|
||||
{
|
||||
public enum WICBitmapPaletteType : int
|
||||
{
|
||||
WICBitmapPaletteTypeCustom = 0x00000000,
|
||||
WICBitmapPaletteTypeMedianCut = 0x00000001,
|
||||
WICBitmapPaletteTypeFixedBW = 0x00000002,
|
||||
WICBitmapPaletteTypeFixedHalftone8 = 0x00000003,
|
||||
WICBitmapPaletteTypeFixedHalftone27 = 0x00000004,
|
||||
WICBitmapPaletteTypeFixedHalftone64 = 0x00000005,
|
||||
WICBitmapPaletteTypeFixedHalftone125 = 0x00000006,
|
||||
WICBitmapPaletteTypeFixedHalftone216 = 0x00000007,
|
||||
WICBitmapPaletteTypeFixedWebPalette = WICBitmapPaletteTypeFixedHalftone216,
|
||||
WICBitmapPaletteTypeFixedHalftone252 = 0x00000008,
|
||||
WICBitmapPaletteTypeFixedHalftone256 = 0x00000009,
|
||||
WICBitmapPaletteTypeFixedGray4 = 0x0000000A,
|
||||
WICBitmapPaletteTypeFixedGray16 = 0x0000000B,
|
||||
WICBitmapPaletteTypeFixedGray256 = 0x0000000C,
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
using System;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
[Flags]
|
||||
public enum WICBitmapTransformOptions : int
|
||||
{
|
||||
WICBitmapTransformRotate0 = 0x00000000,
|
||||
WICBitmapTransformRotate90 = 0x00000001,
|
||||
WICBitmapTransformRotate180 = 0x00000002,
|
||||
WICBitmapTransformRotate270 = 0x00000003,
|
||||
|
||||
WICBitmapTransformFlipHorizontal = 0x00000008,
|
||||
|
||||
WICBitmapTransformFlipVertical = 0x00000010,
|
||||
}
|
||||
}
|
9
src/modules/peek/WIC/Enumerations/WICColorContextType.cs
Normal file
@ -0,0 +1,9 @@
|
||||
namespace WIC
|
||||
{
|
||||
public enum WICColorContextType : int
|
||||
{
|
||||
WICColorContextUninitialized = 0x00000000,
|
||||
WICColorContextProfile = 0x00000001,
|
||||
WICColorContextExifColorSpace = 0x00000002,
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
using System;
|
||||
|
||||
namespace WIC
|
||||
{
|
||||
[Flags]
|
||||
public enum WICComponentEnumerateOptions : int
|
||||
{
|
||||
WICComponentEnumerateDefault = 0x00000000,
|
||||
WICComponentEnumerateRefresh = 0x00000001,
|
||||
WICComponentEnumerateBuiltInOnly = 0x20000000,
|
||||
WICComponentEnumerateUnsigned = 0x40000000,
|
||||
WICComponentEnumerateDisabled = unchecked((int)0x80000000U),
|
||||
}
|
||||
}
|