mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 01:36:31 +02:00
PowerToys Extension: Fancyzone layout command should be able to be pinned into dock (#46198)
<!-- 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 Currently, the layout do not have id, they can't be pinned into dock <img width="1182" height="711" alt="image" src="https://github.com/user-attachments/assets/67461267-4bed-4c07-99ff-7311c368ad09" /> This pr address this and they can be pinned into dock <!-- Please review the items on the PR checklist before submitting--> ## PR Checklist - [ ] Closes: #xxx <!-- - [ ] Closes: #yyy (add separate lines for additional resolved issues) --> - [ ] **Communication:** I've discussed this with core contributors already. If the work hasn't been agreed, this work might be rejected - [ ] **Tests:** Added/updated and all pass - [ ] **Localization:** All end-user-facing strings can be localized - [ ] **Dev docs:** Added/updated - [ ] **New binaries:** Added on the required places - [ ] [JSON for signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json) for new binaries - [ ] [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 <!-- Describe how you validated the behavior. Add automated tests wherever possible, but list manual validation steps taken as well --> ## Validation Steps Performed https://github.com/user-attachments/assets/8e7c8b04-663d-4cd3-b26f-d74e46511feb --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -16,6 +16,7 @@ internal sealed partial class ApplyFancyZonesLayoutCommand : InvokableCommand
|
||||
{
|
||||
_layout = layout;
|
||||
_targetMonitor = monitor;
|
||||
Id = FancyZonesCommandIds.BuildApplyLayoutCommandId(layout, monitor);
|
||||
|
||||
Name = monitor is null ? "Apply to all monitors" : $"Apply to Monitor {monitor.Value.Title}";
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
// 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;
|
||||
|
||||
namespace PowerToysExtension.Helpers;
|
||||
|
||||
internal static class FancyZonesCommandIds
|
||||
{
|
||||
private const string ApplyLayoutPrefix = "com.microsoft.powertoys.fancyzones.layout.apply:";
|
||||
private const string AllMonitorsSuffix = ":all";
|
||||
private const string MonitorMarker = ":monitor:";
|
||||
|
||||
public static string BuildApplyLayoutCommandId(FancyZonesLayoutDescriptor layout, FancyZonesMonitorDescriptor? monitor)
|
||||
{
|
||||
var escapedLayoutId = Uri.EscapeDataString(layout.Id);
|
||||
return monitor is null
|
||||
? $"{ApplyLayoutPrefix}{escapedLayoutId}{AllMonitorsSuffix}"
|
||||
: $"{ApplyLayoutPrefix}{escapedLayoutId}{MonitorMarker}{Uri.EscapeDataString(GetMonitorToken(monitor.Value))}";
|
||||
}
|
||||
|
||||
public static bool TryParseApplyLayoutCommandId(string id, out string layoutId, out string? monitorToken)
|
||||
{
|
||||
layoutId = string.Empty;
|
||||
monitorToken = null;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(id) || !id.StartsWith(ApplyLayoutPrefix, StringComparison.Ordinal))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var payload = id[ApplyLayoutPrefix.Length..];
|
||||
if (payload.EndsWith(AllMonitorsSuffix, StringComparison.Ordinal))
|
||||
{
|
||||
var layoutPayload = payload[..^AllMonitorsSuffix.Length];
|
||||
if (string.IsNullOrWhiteSpace(layoutPayload))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
layoutId = Uri.UnescapeDataString(layoutPayload);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
layoutId = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
return !string.IsNullOrWhiteSpace(layoutId);
|
||||
}
|
||||
|
||||
var monitorMarkerIndex = payload.IndexOf(MonitorMarker, StringComparison.Ordinal);
|
||||
if (monitorMarkerIndex <= 0 || monitorMarkerIndex == payload.Length - MonitorMarker.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var layoutPart = payload[..monitorMarkerIndex];
|
||||
var monitorPart = payload[(monitorMarkerIndex + MonitorMarker.Length)..];
|
||||
if (string.IsNullOrWhiteSpace(layoutPart) || string.IsNullOrWhiteSpace(monitorPart))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
layoutId = Uri.UnescapeDataString(layoutPart);
|
||||
monitorToken = Uri.UnescapeDataString(monitorPart);
|
||||
}
|
||||
catch (ArgumentException)
|
||||
{
|
||||
layoutId = string.Empty;
|
||||
monitorToken = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return !string.IsNullOrWhiteSpace(layoutId) && !string.IsNullOrWhiteSpace(monitorToken);
|
||||
}
|
||||
|
||||
public static string GetMonitorToken(FancyZonesMonitorDescriptor monitor)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(monitor.Data.MonitorInstanceId))
|
||||
{
|
||||
return $"instance:{monitor.Data.MonitorInstanceId}";
|
||||
}
|
||||
|
||||
return $"fallback:{monitor.Data.Monitor}|{monitor.Data.MonitorNumber}";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
// 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 System.Globalization;
|
||||
using System.Text;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Properties;
|
||||
|
||||
namespace PowerToysExtension.Helpers;
|
||||
|
||||
internal static class FancyZonesContextHelper
|
||||
{
|
||||
private static readonly CompositeFormat ApplyToMonitorFormat = CompositeFormat.Parse(Resources.FancyZones_ApplyTo_Format);
|
||||
|
||||
public static string FormatApplyToMonitorTitle(FancyZonesMonitorDescriptor monitor)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, ApplyToMonitorFormat, monitor.Title);
|
||||
}
|
||||
|
||||
public static IContextItem[] BuildLayoutContext(FancyZonesLayoutDescriptor layout, IReadOnlyList<FancyZonesMonitorDescriptor> monitors)
|
||||
{
|
||||
var commands = new List<IContextItem>(monitors.Count);
|
||||
|
||||
foreach (var monitor in monitors)
|
||||
{
|
||||
commands.Add(new CommandContextItem(new ApplyFancyZonesLayoutCommand(layout, monitor))
|
||||
{
|
||||
Title = FormatApplyToMonitorTitle(monitor),
|
||||
Subtitle = monitor.Subtitle,
|
||||
});
|
||||
}
|
||||
|
||||
return commands.ToArray();
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
@@ -70,7 +69,7 @@ internal sealed partial class FancyZonesLayoutsPage : DynamicListPage
|
||||
|
||||
var item = new FancyZonesLayoutListItem(defaultCommand, layout, fallbackIcon)
|
||||
{
|
||||
MoreCommands = BuildLayoutContext(layout, monitors),
|
||||
MoreCommands = FancyZonesContextHelper.BuildLayoutContext(layout, monitors),
|
||||
};
|
||||
|
||||
items.Add(item);
|
||||
@@ -84,21 +83,4 @@ internal sealed partial class FancyZonesLayoutsPage : DynamicListPage
|
||||
return Array.Empty<IListItem>();
|
||||
}
|
||||
}
|
||||
|
||||
private static IContextItem[] BuildLayoutContext(FancyZonesLayoutDescriptor layout, IReadOnlyList<FancyZonesMonitorDescriptor> monitors)
|
||||
{
|
||||
var commands = new List<IContextItem>(monitors.Count);
|
||||
|
||||
for (var i = 0; i < monitors.Count; i++)
|
||||
{
|
||||
var monitor = monitors[i];
|
||||
commands.Add(new CommandContextItem(new ApplyFancyZonesLayoutCommand(layout, monitor))
|
||||
{
|
||||
Title = string.Format(CultureInfo.CurrentCulture, "Apply to {0}", monitor.Title),
|
||||
Subtitle = monitor.Subtitle,
|
||||
});
|
||||
}
|
||||
|
||||
return commands.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,14 @@
|
||||
// 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.Linq;
|
||||
using Microsoft.CommandPalette.Extensions;
|
||||
using Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
using PowerToysExtension.Commands;
|
||||
using PowerToysExtension.Helpers;
|
||||
using PowerToysExtension.Pages;
|
||||
using PowerToysExtension.Properties;
|
||||
|
||||
namespace PowerToysExtension;
|
||||
@@ -64,11 +68,54 @@ public partial class PowerToysExtensionCommandsProvider : CommandProvider
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return TryGetFancyZonesCommandItem(id);
|
||||
}
|
||||
|
||||
private void RaiseModuleItemsChanged()
|
||||
{
|
||||
RaiseItemsChanged();
|
||||
}
|
||||
|
||||
private static ICommandItem? TryGetFancyZonesCommandItem(string id)
|
||||
{
|
||||
if (!FancyZonesCommandIds.TryParseApplyLayoutCommandId(id, out var layoutId, out var monitorToken))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var layout = FancyZonesDataService.GetLayouts()
|
||||
.FirstOrDefault(candidate => string.Equals(candidate.Id, layoutId, StringComparison.Ordinal));
|
||||
if (layout is null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var fallbackIcon = PowerToysResourcesHelper.IconFromSettingsIcon("FancyZones.png");
|
||||
if (string.IsNullOrWhiteSpace(monitorToken))
|
||||
{
|
||||
FancyZonesDataService.TryGetMonitors(out var monitors, out _);
|
||||
return new FancyZonesLayoutListItem(new ApplyFancyZonesLayoutCommand(layout, monitor: null), layout, fallbackIcon)
|
||||
{
|
||||
MoreCommands = FancyZonesContextHelper.BuildLayoutContext(layout, monitors),
|
||||
};
|
||||
}
|
||||
|
||||
if (!FancyZonesDataService.TryGetMonitors(out var availableMonitors, out _))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var monitor = availableMonitors
|
||||
.FirstOrDefault(candidate => string.Equals(FancyZonesCommandIds.GetMonitorToken(candidate), monitorToken, StringComparison.Ordinal));
|
||||
|
||||
if (monitor.Equals(default(FancyZonesMonitorDescriptor)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new FancyZonesLayoutListItem(new ApplyFancyZonesLayoutCommand(layout, monitor), layout, fallbackIcon)
|
||||
{
|
||||
Subtitle = FancyZonesContextHelper.FormatApplyToMonitorTitle(monitor),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user