Adds BgcodeThumbnailProvider and BgcodePreviewHandler (#38667)

<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request

<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [X] **Closes:** #30352
- [X] **Communication:** I've discussed this with core contributors
already. If work hasn't been agreed, this work might be rejected
- [X] **Tests:** Added/updated and all pass
- [X] **Localization:** All end user facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [X] **New binaries:** Added on the required places
- [X] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [X] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments


![image](https://github.com/user-attachments/assets/62c0cbbb-fbca-4bb3-82fe-696ba40da83d)


![image](https://github.com/user-attachments/assets/3f2f1346-91fb-4f49-85b9-8cd6e19e68e9)

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

- Close PowerToys if installed in your machine
- Full build the solution: PowerToys.sln
- Start PowerToys from PowerToys\x64\Debug\PowerToys.exe or
PowerToys\x64\Release\PowerToys.exe
- Toggle the "Binary G-code thumbnail previewer" setting to enable
- Open HelperFiles folder on the tests and check if the icon changes to
an image
- Check explorer preview to see if image is also shown there

---------

Co-authored-by: leileizhang <leilzh@microsoft.com>
This commit is contained in:
Pedro Lamas
2025-07-10 10:20:30 +01:00
committed by GitHub
parent 1feb7d5e5c
commit 071f5d7bcc
86 changed files with 3440 additions and 10 deletions

View File

@@ -223,6 +223,23 @@ namespace Microsoft.PowerToys.Settings.UI.Library
}
}
private bool enableBgcodePreview = true;
[JsonPropertyName("bgcode-previewer-toggle-setting")]
[JsonConverter(typeof(BoolPropertyJsonConverter))]
public bool EnableBgcodePreview
{
get => enableBgcodePreview;
set
{
if (value != enableBgcodePreview)
{
LogTelemetryEvent(value);
enableBgcodePreview = value;
}
}
}
private bool enableGcodeThumbnail = true;
[JsonPropertyName("gcode-thumbnail-toggle-setting")]
@@ -240,6 +257,23 @@ namespace Microsoft.PowerToys.Settings.UI.Library
}
}
private bool enableBgcodeThumbnail = true;
[JsonPropertyName("bgcode-thumbnail-toggle-setting")]
[JsonConverter(typeof(BoolPropertyJsonConverter))]
public bool EnableBgcodeThumbnail
{
get => enableBgcodeThumbnail;
set
{
if (value != enableBgcodeThumbnail)
{
LogTelemetryEvent(value);
enableBgcodeThumbnail = value;
}
}
}
private bool enableStlThumbnail = true;
[JsonPropertyName("stl-thumbnail-toggle-setting")]

View File

@@ -61,11 +61,13 @@ namespace ViewModelTests
Assert.AreEqual(originalSettings.Properties.EnableMonacoPreview, viewModel.MonacoRenderIsEnabled);
Assert.AreEqual(originalSettings.Properties.EnablePdfPreview, viewModel.PDFRenderIsEnabled);
Assert.AreEqual(originalSettings.Properties.EnableGcodePreview, viewModel.GCODERenderIsEnabled);
Assert.AreEqual(originalSettings.Properties.EnableBgcodePreview, viewModel.BGCODERenderIsEnabled);
Assert.AreEqual(originalSettings.Properties.EnableQoiPreview, viewModel.QOIRenderIsEnabled);
Assert.AreEqual(originalSettings.Properties.EnableSvgPreview, viewModel.SVGRenderIsEnabled);
Assert.AreEqual(originalSettings.Properties.EnableSvgThumbnail, viewModel.SVGThumbnailIsEnabled);
Assert.AreEqual(originalSettings.Properties.EnablePdfThumbnail, viewModel.PDFThumbnailIsEnabled);
Assert.AreEqual(originalSettings.Properties.EnableGcodeThumbnail, viewModel.GCODEThumbnailIsEnabled);
Assert.AreEqual(originalSettings.Properties.EnableBgcodeThumbnail, viewModel.BGCODEThumbnailIsEnabled);
Assert.AreEqual(originalSettings.Properties.EnableStlThumbnail, viewModel.STLThumbnailIsEnabled);
Assert.AreEqual(originalSettings.Properties.EnableQoiThumbnail, viewModel.QOIThumbnailIsEnabled);
@@ -146,6 +148,24 @@ namespace ViewModelTests
viewModel.GCODEThumbnailIsEnabled = true;
}
[TestMethod]
public void BGCODEThumbnailIsEnabledShouldPrevHandlerWhenSuccessful()
{
// Assert
Func<string, int> sendMockIPCConfigMSG = msg =>
{
SndModuleSettings<SndPowerPreviewSettings> snd = JsonSerializer.Deserialize<SndModuleSettings<SndPowerPreviewSettings>>(msg);
Assert.IsTrue(snd.PowertoysSetting.FileExplorerPreviewSettings.Properties.EnableBgcodeThumbnail);
return 0;
};
// arrange
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(mockPowerPreviewSettingsUtils.Object), SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, PowerPreviewSettings.ModuleName);
// act
viewModel.BGCODEThumbnailIsEnabled = true;
}
[TestMethod]
public void STLThumbnailIsEnabledShouldPrevHandlerWhenSuccessful()
{
@@ -254,6 +274,24 @@ namespace ViewModelTests
viewModel.GCODERenderIsEnabled = true;
}
[TestMethod]
public void BGCODERenderIsEnabledShouldPrevHandlerWhenSuccessful()
{
// Assert
Func<string, int> sendMockIPCConfigMSG = msg =>
{
SndModuleSettings<SndPowerPreviewSettings> snd = JsonSerializer.Deserialize<SndModuleSettings<SndPowerPreviewSettings>>(msg);
Assert.IsTrue(snd.PowertoysSetting.FileExplorerPreviewSettings.Properties.EnableBgcodePreview);
return 0;
};
// arrange
PowerPreviewViewModel viewModel = new PowerPreviewViewModel(SettingsRepository<PowerPreviewSettings>.GetInstance(mockPowerPreviewSettingsUtils.Object), SettingsRepository<GeneralSettings>.GetInstance(mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, PowerPreviewSettings.ModuleName);
// act
viewModel.BGCODERenderIsEnabled = true;
}
[TestMethod]
public void QOIRenderIsEnabledShouldPrevHandlerWhenSuccessful()
{

View File

@@ -147,8 +147,18 @@
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard
x:Uid="FileExplorerPreview_ToggleSwitch_Preview_QOI"
x:Uid="FileExplorerPreview_ToggleSwitch_Preview_BGCODE"
HeaderIcon="{ui:FontIcon Glyph=&#xE914;}"
IsEnabled="{x:Bind ViewModel.BGCODERenderIsGpoDisabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
<ToggleSwitch
x:Uid="ToggleSwitch"
IsEnabled="{x:Bind ViewModel.BGCODERenderIsGpoEnabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
IsOn="{x:Bind ViewModel.BGCODERenderIsEnabled, Mode=TwoWay}" />
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard
x:Uid="FileExplorerPreview_ToggleSwitch_Preview_QOI"
HeaderIcon="{ui:FontIcon Glyph=&#xE91B;}"
IsEnabled="{x:Bind ViewModel.QOIRenderIsGpoDisabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
<ToggleSwitch
x:Uid="ToggleSwitch"
@@ -212,8 +222,18 @@
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard
x:Uid="FileExplorerPreview_ToggleSwitch_Thumbnail_QOI"
x:Uid="FileExplorerPreview_ToggleSwitch_Thumbnail_BGCODE"
HeaderIcon="{ui:FontIcon Glyph=&#xE914;}"
IsEnabled="{x:Bind ViewModel.BGCODEThumbnailIsGpoDisabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
<ToggleSwitch
x:Uid="ToggleSwitch"
IsEnabled="{x:Bind ViewModel.BGCODEThumbnailIsGpoEnabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
IsOn="{x:Bind ViewModel.BGCODEThumbnailIsEnabled, Mode=TwoWay}" />
</tkcontrols:SettingsCard>
<tkcontrols:SettingsCard
x:Uid="FileExplorerPreview_ToggleSwitch_Thumbnail_QOI"
HeaderIcon="{ui:FontIcon Glyph=&#xE91B;}"
IsEnabled="{x:Bind ViewModel.QOIThumbnailIsGpoDisabled, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}">
<ToggleSwitch
x:Uid="ToggleSwitch"
@@ -244,7 +264,7 @@
</controls:SettingsPageControl.PrimaryLinks>
<controls:SettingsPageControl.SecondaryLinks>
<controls:PageLink Link="https://noraajunker.ch" Text="Noraa Junker's work on developer file preview" />
<controls:PageLink Link="https://www.pedrolamas.com" Text="Pedro Lamas's work on G-Code, STL, and QOI" />
<controls:PageLink Link="https://www.pedrolamas.com" Text="Pedro Lamas's work on G-Code, Binary G-Code, STL, and QOI" />
</controls:SettingsPageControl.SecondaryLinks>
</controls:SettingsPageControl>
</Page>

View File

@@ -2002,7 +2002,7 @@ Made with 💗 by Microsoft and the PowerToys community.</value>
<value>File Locksmith lists which processes are using the selected files or directories and allows closing those processes.</value>
</data>
<data name="Oobe_FileExplorer.Description" xml:space="preserve">
<value>PowerToys introduces add-ons to the Windows File Explorer that will enable files like Markdown (.md), PDF (.pdf), SVG (.svg), STL (.stl), G-code (.gcode) and developer files to be viewed in the preview pane. It introduces File Explorer thumbnail support for a number of these file types as well.</value>
<value>PowerToys introduces add-ons to the Windows File Explorer that will enable files like Markdown (.md), PDF (.pdf), SVG (.svg), STL (.stl), G-code (.gcode), Binary G-code (.bgcode), and developer files to be viewed in the preview pane. It introduces File Explorer thumbnail support for a number of these file types as well.</value>
</data>
<data name="Oobe_ImageResizer.Description" xml:space="preserve">
<value>Image Resizer is a Windows shell extension for simple bulk image-resizing.</value>
@@ -5015,6 +5015,18 @@ To record a specific window, enter the hotkey with the Alt key in the opposite m
<data name="BugReportUnderConstruction" xml:space="preserve">
<value>Bug report package is being created</value>
</data>
<data name="FileExplorerPreview_ToggleSwitch_Preview_BGCODE.Header" xml:space="preserve">
<value>Binary Geometric Code</value>
</data>
<data name="FileExplorerPreview_ToggleSwitch_Preview_BGCODE.Description" xml:space="preserve">
<value>.bgcode</value>
</data>
<data name="FileExplorerPreview_ToggleSwitch_Thumbnail_BGCODE.Description" xml:space="preserve">
<value>.bgcode</value>
</data>
<data name="FileExplorerPreview_ToggleSwitch_Thumbnail_BGCODE.Header" xml:space="preserve">
<value>Binary Geometric Code</value>
</data>
<data name="HighlightMode.Description" xml:space="preserve">
<value>Highlight the cursor or dim the screen to spotlight it</value>
</data>

View File

@@ -125,6 +125,20 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
_gcodeRenderIsEnabled = Settings.Properties.EnableGcodePreview;
}
_bgcodeRenderEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredBgcodePreviewEnabledValue();
if (_bgcodeRenderEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _bgcodeRenderEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
{
// Get the enabled state from GPO.
_bgcodeRenderEnabledStateIsGPOConfigured = true;
_bgcodeRenderIsEnabled = _bgcodeRenderEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
_bgcodeRenderIsGpoEnabled = _bgcodeRenderEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
_bgcodeRenderIsGpoDisabled = _bgcodeRenderEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled;
}
else
{
_bgcodeRenderIsEnabled = Settings.Properties.EnableBgcodePreview;
}
_qoiRenderEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredQoiPreviewEnabledValue();
if (_qoiRenderEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _qoiRenderEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
{
@@ -181,6 +195,20 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
_gcodeThumbnailIsEnabled = Settings.Properties.EnableGcodeThumbnail;
}
_bgcodeThumbnailEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredBgcodeThumbnailsEnabledValue();
if (_bgcodeThumbnailEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _bgcodeThumbnailEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
{
// Get the enabled state from GPO.
_bgcodeThumbnailEnabledStateIsGPOConfigured = true;
_bgcodeThumbnailIsEnabled = _bgcodeThumbnailEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
_bgcodeThumbnailIsGpoEnabled = _bgcodeThumbnailEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
_bgcodeThumbnailIsGpoDisabled = _bgcodeThumbnailEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled;
}
else
{
_bgcodeThumbnailIsEnabled = Settings.Properties.EnableBgcodeThumbnail;
}
_stlThumbnailEnabledGpoRuleConfiguration = GPOWrapper.GetConfiguredStlThumbnailsEnabledValue();
if (_stlThumbnailEnabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _stlThumbnailEnabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
{
@@ -251,6 +279,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private bool _gcodeRenderIsGpoDisabled;
private bool _gcodeRenderIsEnabled;
private GpoRuleConfigured _bgcodeRenderEnabledGpoRuleConfiguration;
private bool _bgcodeRenderEnabledStateIsGPOConfigured;
private bool _bgcodeRenderIsGpoEnabled;
private bool _bgcodeRenderIsGpoDisabled;
private bool _bgcodeRenderIsEnabled;
private GpoRuleConfigured _qoiRenderEnabledGpoRuleConfiguration;
private bool _qoiRenderEnabledStateIsGPOConfigured;
private bool _qoiRenderIsGpoEnabled;
@@ -275,6 +309,12 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
private bool _gcodeThumbnailIsGpoDisabled;
private bool _gcodeThumbnailIsEnabled;
private GpoRuleConfigured _bgcodeThumbnailEnabledGpoRuleConfiguration;
private bool _bgcodeThumbnailEnabledStateIsGPOConfigured;
private bool _bgcodeThumbnailIsGpoEnabled;
private bool _bgcodeThumbnailIsGpoDisabled;
private bool _bgcodeThumbnailIsEnabled;
private GpoRuleConfigured _stlThumbnailEnabledGpoRuleConfiguration;
private bool _stlThumbnailEnabledStateIsGPOConfigured;
private bool _stlThumbnailIsGpoEnabled;
@@ -294,7 +334,8 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
return _svgRenderEnabledStateIsGPOConfigured || _mdRenderEnabledStateIsGPOConfigured
|| _monacoRenderEnabledStateIsGPOConfigured || _pdfRenderEnabledStateIsGPOConfigured
|| _gcodeRenderEnabledStateIsGPOConfigured || _qoiRenderEnabledStateIsGPOConfigured;
|| _gcodeRenderEnabledStateIsGPOConfigured || _qoiRenderEnabledStateIsGPOConfigured
|| _bgcodeRenderEnabledStateIsGPOConfigured;
}
}
@@ -304,7 +345,7 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
{
return _svgThumbnailEnabledStateIsGPOConfigured || _pdfThumbnailEnabledStateIsGPOConfigured
|| _gcodeThumbnailEnabledStateIsGPOConfigured || _stlThumbnailEnabledStateIsGPOConfigured
|| _qoiThumbnailEnabledStateIsGPOConfigured;
|| _qoiThumbnailEnabledStateIsGPOConfigured || _bgcodeThumbnailEnabledStateIsGPOConfigured;
}
}
@@ -778,6 +819,48 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
}
}
public bool BGCODERenderIsEnabled
{
get
{
return _bgcodeRenderIsEnabled;
}
set
{
if (_bgcodeRenderEnabledStateIsGPOConfigured)
{
// If it's GPO configured, shouldn't be able to change this state.
return;
}
if (value != _bgcodeRenderIsEnabled)
{
_bgcodeRenderIsEnabled = value;
Settings.Properties.EnableBgcodePreview = value;
RaisePropertyChanged();
}
}
}
// Used to only disable enabled button on forced enabled state. (With this users still able to change the utility properties.)
public bool BGCODERenderIsGpoEnabled
{
get
{
return _bgcodeRenderIsGpoEnabled;
}
}
// Used to disable the settings card on forced disabled state.
public bool BGCODERenderIsGpoDisabled
{
get
{
return _bgcodeRenderIsGpoDisabled;
}
}
public bool GCODEThumbnailIsEnabled
{
get
@@ -820,6 +903,48 @@ namespace Microsoft.PowerToys.Settings.UI.ViewModels
}
}
public bool BGCODEThumbnailIsEnabled
{
get
{
return _bgcodeThumbnailIsEnabled;
}
set
{
if (_bgcodeThumbnailEnabledStateIsGPOConfigured)
{
// If it's GPO configured, shouldn't be able to change this state.
return;
}
if (value != _bgcodeThumbnailIsEnabled)
{
_bgcodeThumbnailIsEnabled = value;
Settings.Properties.EnableBgcodeThumbnail = value;
RaisePropertyChanged();
}
}
}
// Used to only disable enabled button on forced enabled state. (With this users still able to change the utility properties.)
public bool BGCODEThumbnailIsGpoEnabled
{
get
{
return _bgcodeThumbnailIsGpoEnabled;
}
}
// Used to disable the settings card on forced disabled state.
public bool BGCODEThumbnailIsGpoDisabled
{
get
{
return _bgcodeThumbnailIsGpoDisabled;
}
}
public bool STLThumbnailIsEnabled
{
get