Compare commits

...

4 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
a27ede20e4 Fix JSON property name to match C++ backend
Co-authored-by: yeelam-gordon <73506701+yeelam-gordon@users.noreply.github.com>
2026-02-05 15:23:25 +00:00
copilot-swe-agent[bot]
4b4e408cdd Add test for ExtendedContextMenuOnly setting
Co-authored-by: yeelam-gordon <73506701+yeelam-gordon@users.noreply.github.com>
2026-02-05 15:21:31 +00:00
copilot-swe-agent[bot]
3e869f3347 Add extended context menu setting for Image Resizer
Co-authored-by: yeelam-gordon <73506701+yeelam-gordon@users.noreply.github.com>
2026-02-05 15:20:36 +00:00
copilot-swe-agent[bot]
9dd1056e9a Initial plan 2026-02-05 15:17:02 +00:00
8 changed files with 87 additions and 1 deletions

View File

@@ -12,6 +12,7 @@ namespace
const wchar_t c_imageResizerDataFilePath[] = L"\\image-resizer-settings.json";
const wchar_t c_rootRegPath[] = L"Software\\Microsoft\\ImageResizer";
const wchar_t c_enabled[] = L"enabled";
const wchar_t c_extendedContextMenuOnly[] = L"ExtendedContextMenuOnly";
const wchar_t c_ImageResizer[] = L"Image Resizer";
unsigned int RegReadInteger(const std::wstring& valueName, unsigned int defaultValue)
@@ -64,6 +65,8 @@ void CSettings::Save()
{
json::JsonObject jsonData;
jsonData.SetNamedValue(c_extendedContextMenuOnly, json::value(settings.extendedContextMenuOnly));
json::to_file(jsonFilePath, jsonData);
GetSystemTimeAsFileTime(&lastLoadedTime);
}
@@ -122,6 +125,7 @@ void CSettings::Reload()
void CSettings::MigrateFromRegistry()
{
settings.enabled = RegReadBoolean(c_enabled, true);
settings.extendedContextMenuOnly = RegReadBoolean(c_extendedContextMenuOnly, false); // Disabled by default.
}
void CSettings::ParseJson()
@@ -132,7 +136,10 @@ void CSettings::ParseJson()
const json::JsonObject& jsonSettings = json.value();
try
{
// NB: add any new settings here
if (json::has(jsonSettings, c_extendedContextMenuOnly, json::JsonValueType::Boolean))
{
settings.extendedContextMenuOnly = jsonSettings.GetNamedBoolean(c_extendedContextMenuOnly);
}
}
catch (const winrt::hresult_error&)
{

View File

@@ -19,6 +19,16 @@ public:
return settings.enabled;
}
inline bool GetExtendedContextMenuOnly() const
{
return settings.extendedContextMenuOnly;
}
inline void SetExtendedContextMenuOnly(bool extendedOnly)
{
settings.extendedContextMenuOnly = extendedOnly;
}
void Save();
void Load();
@@ -26,6 +36,7 @@ private:
struct Settings
{
bool enabled{ true };
bool extendedContextMenuOnly{ false }; // Disabled by default.
};
void RefreshEnabledState();

View File

@@ -70,6 +70,10 @@ HRESULT CContextMenuHandler::QueryContextMenu(_In_ HMENU hmenu, UINT indexMenu,
if (!CSettingsInstance().GetEnabled())
return E_FAIL;
// Check if we should only be on the extended context menu
if (CSettingsInstance().GetExtendedContextMenuOnly() && (!(uFlags & CMF_EXTENDEDVERBS)))
return E_FAIL;
// NB: We just check the first item. We could iterate through more if the first one doesn't meet the criteria
HDropIterator i(m_pdtobj);
i.First();

View File

@@ -27,6 +27,7 @@ namespace Microsoft.PowerToys.Settings.UI.Library
ImageresizerKeepDateModified = new BoolProperty();
ImageresizerFallbackEncoder = new StringProperty(new System.Guid("19e4a5aa-5662-4fc5-a0c0-1758028e1057").ToString());
ImageresizerCustomSize = new ImageResizerCustomSizeProperty(new ImageSize(4, "custom", ResizeFit.Fit, 1024, 640, ResizeUnit.Pixel));
ExtendedContextMenuOnly = new BoolProperty();
}
public ImageResizerProperties(Func<string, string> resourceLoader)
@@ -84,6 +85,9 @@ namespace Microsoft.PowerToys.Settings.UI.Library
[CmdConfigureIgnoreAttribute]
public ImageResizerCustomSizeProperty ImageresizerCustomSize { get; set; }
[JsonPropertyName("ExtendedContextMenuOnly")]
public BoolProperty ExtendedContextMenuOnly { get; set; }
public string ToJsonString()
{
return JsonSerializer.Serialize(this, SettingsSerializationContext.Default.ImageResizerProperties);

View File

@@ -204,6 +204,23 @@ namespace ViewModelTests
Assert.AreEqual(3, viewModel.Encoder);
}
[TestMethod]
public void ExtendedContextMenuOnlyShouldUpdateValueWhenSuccessful()
{
// arrange
var fileSystemMock = new MockFileSystem();
var mockSettingsUtils = new SettingsUtils(fileSystemMock);
Func<string, int> sendMockIPCConfigMSG = msg => { return 0; };
ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository<GeneralSettings>.GetInstance(_mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, (string name) => name);
// act
viewModel.ExtendedContextMenuOnly = true;
// Assert
viewModel = new ImageResizerViewModel(mockSettingsUtils, SettingsRepository<GeneralSettings>.GetInstance(_mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, (string name) => name);
Assert.IsTrue(viewModel.ExtendedContextMenuOnly);
}
[TestMethod]
public void AddImageSizeShouldAddNewImageSizeWhenSuccessful()
{

View File

@@ -39,6 +39,25 @@
<ToggleSwitch x:Uid="ToggleSwitch" IsOn="{x:Bind ViewModel.IsEnabled, Mode=TwoWay}" />
</tkcontrols:SettingsCard>
</controls:GPOInfoControl>
<controls:SettingsGroup x:Uid="ImageResizer_ShellIntegration" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
<tkcontrols:SettingsCard
Name="ImageResizerToggleContextMenu"
x:Uid="ImageResizer_Toggle_ContextMenu">
<ComboBox
MinWidth="{StaticResource SettingActionControlMinWidth}"
AutomationProperties.Name="{Binding ElementName=ImageResizerToggleContextMenu, Path=Header}"
SelectedIndex="{x:Bind ViewModel.ExtendedContextMenuOnly, Mode=TwoWay, Converter={StaticResource BoolToComboBoxIndexConverter}}">
<ComboBoxItem x:Uid="ImageResizer_Toggle_StandardContextMenu" />
<ComboBoxItem x:Uid="ImageResizer_Toggle_ExtendedContextMenu" />
</ComboBox>
</tkcontrols:SettingsCard>
<InfoBar
x:Uid="ExtendedContextMenuInfo"
IsClosable="False"
IsOpen="True"
IsTabStop="True"
Severity="Informational" />
</controls:SettingsGroup>
<controls:SettingsGroup x:Uid="ImageResizer_CustomSizes" IsEnabled="{x:Bind ViewModel.IsEnabled, Mode=OneWay}">
<tkcontrols:SettingsCard
Name="ImageResizerPresets"

View File

@@ -1274,6 +1274,18 @@ Please review the placeholder content that represents the final terms and usage
<value>Image Resizer</value>
<comment>do not loc the Product name. Do you want this feature on / off</comment>
</data>
<data name="ImageResizer_ShellIntegration.Header" xml:space="preserve">
<value>Shell integration</value>
</data>
<data name="ImageResizer_Toggle_ContextMenu.Header" xml:space="preserve">
<value>Show Image Resizer in</value>
</data>
<data name="ImageResizer_Toggle_StandardContextMenu.Content" xml:space="preserve">
<value>Default and extended context menu</value>
</data>
<data name="ImageResizer_Toggle_ExtendedContextMenu.Content" xml:space="preserve">
<value>Extended context menu only</value>
</data>
<data name="ImagesSizesListView.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Image Size</value>
</data>

View File

@@ -94,6 +94,7 @@ public partial class ImageResizerViewModel : Observable
FileName = Settings.Properties.ImageresizerFileName.Value;
KeepDateModified = Settings.Properties.ImageresizerKeepDateModified.Value;
Encoder = GetEncoderIndex(Settings.Properties.ImageresizerFallbackEncoder.Value);
ExtendedContextMenuOnly = Settings.Properties.ExtendedContextMenuOnly.Value;
_customSize = Settings.Properties.ImageresizerCustomSize.Value;
@@ -125,6 +126,7 @@ public partial class ImageResizerViewModel : Observable
private string _fileName;
private bool _keepDateModified;
private int _encoderGuidId;
private bool _extendedContextMenuOnly;
public bool IsListViewFocusRequested { get; set; }
@@ -295,6 +297,16 @@ public partial class ImageResizerViewModel : Observable
}
}
public bool ExtendedContextMenuOnly
{
get => _extendedContextMenuOnly;
set
{
SetProperty(ref _extendedContextMenuOnly, value, v => Settings.Properties.ExtendedContextMenuOnly.Value = v);
}
}
public string EncoderGuid => GetEncoderGuid(_encoderGuidId);
public static string GetEncoderGuid(int index) =>