mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-02-06 11:20:11 +01:00
Compare commits
2 Commits
copilot/fi
...
dev/migrie
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89c3229658 | ||
|
|
78378e1d0a |
1
.github/actions/spell-check/allow/names.txt
vendored
1
.github/actions/spell-check/allow/names.txt
vendored
@@ -206,6 +206,7 @@ Bilibili
|
||||
BVID
|
||||
capturevideosample
|
||||
cmdow
|
||||
Contoso
|
||||
Controlz
|
||||
cortana
|
||||
devhints
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
author: Mike Griese
|
||||
created on: 2024-07-19
|
||||
last updated: 2025-08-08
|
||||
last updated: 2026-02-05
|
||||
issue id: n/a
|
||||
---
|
||||
|
||||
@@ -75,6 +75,8 @@ functionality.
|
||||
- [Advanced scenarios](#advanced-scenarios)
|
||||
- [Status messages](#status-messages)
|
||||
- [Rendering of ICommandItems in Lists and Menus](#rendering-of-icommanditems-in-lists-and-menus)
|
||||
- [Addenda I: API additions (ICommandProvider2)](#addenda-i-api-additions-icommandprovider2)
|
||||
- [Addenda IV: Dock bands](#addenda-iv-dock-bands)
|
||||
- [Class diagram](#class-diagram)
|
||||
- [Future considerations](#future-considerations)
|
||||
- [Arbitrary parameters and arguments](#arbitrary-parameters-and-arguments)
|
||||
@@ -2045,6 +2047,87 @@ Fortunately, we can put all of that (`GetApiExtensionStubs`,
|
||||
developers won't have to do anything. The toolkit will just do the right thing
|
||||
for them.
|
||||
|
||||
## Addenda IV: Dock bands
|
||||
|
||||
The "dock" is another way to surface commands to the user. This is a
|
||||
toolbar-like window that can be docked to the side of the screen, or floated as
|
||||
its own window. It enables another surface for extensions to display real-time
|
||||
information and shortcuts to users.
|
||||
|
||||
Bands are powered by the same interfaces as DevPal itself. Extensions can provide
|
||||
bands via the new `DockBand` property on `ICommandProvider3`.
|
||||
|
||||
```csharp
|
||||
interface ICommandProvider3 requires ICommandProvider2
|
||||
{
|
||||
ICommandItem[] GetDockBands();
|
||||
};
|
||||
```
|
||||
|
||||
A **Dock Band** is one "strip of items" in the dock. Each band can have multiple
|
||||
items. This allows an extension to create a strip of buttons that should all be
|
||||
treated as a single unit. For example, a media player band will want probably
|
||||
four items:
|
||||
* one for the previous track
|
||||
* one for play/pause
|
||||
* one for next track
|
||||
* and one to display the album art and track title
|
||||
|
||||
`GetDockBands` returns an array of `ICommandItem`s. Each `ICommandItem`
|
||||
represents one band in the dock. These represent all of the bands that an
|
||||
extension would allow the user to add to their dock.
|
||||
|
||||
All of the `ICommandItem`s returned from `GetDockBands` **must** have a
|
||||
`Command` with a non-empty `Id` set. If the `Id` is null or empty, DevPal will
|
||||
ignore that band.
|
||||
|
||||
Bands are not automatically added to the dock. Instead, the user must choose
|
||||
which bands they want to add. This is done via the DevPal settings page.
|
||||
Furthermore, bands are not displayed in the list of commands in DevPal itself.
|
||||
This allows extension authors to create objects that are only intended for the
|
||||
dock, without cluttering up the main DevPal UI, and vice versa.
|
||||
|
||||
DevPal will then create UI in the dock for each band the user has chosen to add.
|
||||
What that looks like will depend on the `Command` in the `ICommandItem`:
|
||||
* A `IInvokableCommand` will be rendered as a single button. Think "the
|
||||
time/date" button on the taskbar, that opens the notification center.
|
||||
* A `IListPage` will be rendered as a strip of buttons, one for each `IListItem`
|
||||
in the list. Think "media controls" for a music player.
|
||||
* A `IContentPage` will be rendered as a single button. Clicking that button
|
||||
will open a flyout with that content rendered in it. Think "weather" or "news"
|
||||
flyouts.
|
||||
|
||||
If the `Command` in the `IListItem`s of a band are pages, then clicking those
|
||||
buttons will open DevPal to that page, as if it were a flyout from the dock.
|
||||
|
||||
The `.Title` property of the top-level `ICommandItem` representing the band will
|
||||
be used as the name of the band in the settings. So a media player band might
|
||||
want to set the `Title` to "Contoso Music Player", even if the individual
|
||||
buttons in the band don't show that title.
|
||||
|
||||
Users may also "pin" a top-level command from DevPal into the dock. DevPal will
|
||||
take care of creating a new band (owned by devpal) with that command in it. This
|
||||
allows users to add quick shortcuts to their favorite commands in the dock.
|
||||
Think: pinning an app, or pinning a particular GitHub query.
|
||||
|
||||
Bands are added via ID. An extension may choose to have a TopLevelCommand and a
|
||||
DockBand with the same `Id`. In this case, if the user pins the TopLevelCommand
|
||||
to the dock, DevPal will pin the band from `GetDockBands`, rather than creating
|
||||
a simple pinned command. This allows extension authors to seamlessly have a
|
||||
top-level command present a palette-specific experience, while also having a
|
||||
dock-specific experience. In our ongoing media player example, the top-level
|
||||
command might open DevPal to a full-featured music control page, while the dock
|
||||
band has simpler buttons on it (without a title/subtitle).
|
||||
|
||||
Users may choose to have:
|
||||
* the orientation of the dock: vertical or horizontal
|
||||
* the size of the dock
|
||||
* which bands are shown in the dock
|
||||
* whether the "labels" (read: `Title` & `Subtitle`) of individual bands are
|
||||
shown or hidden.
|
||||
- Dock bands will still display the `Title` & `Subtitle` of each item in the
|
||||
band as the tooltip on those items, even when the "labels" are hidden.
|
||||
|
||||
## Class diagram
|
||||
|
||||
This is a diagram attempting to show the relationships between the various types we've defined for the SDK. Some elements are omitted for clarity. (Notably, `IconData` and `IPropChanged`, which are used in many places.)
|
||||
|
||||
@@ -6,7 +6,10 @@ using Windows.Foundation;
|
||||
|
||||
namespace Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
public abstract partial class CommandProvider : ICommandProvider, ICommandProvider2
|
||||
public abstract partial class CommandProvider :
|
||||
ICommandProvider,
|
||||
ICommandProvider2,
|
||||
ICommandProvider3
|
||||
{
|
||||
public virtual string Id { get; protected set; } = string.Empty;
|
||||
|
||||
@@ -48,6 +51,21 @@ public abstract partial class CommandProvider : ICommandProvider, ICommandProvid
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the dock bands provided by this command provider. Dock bands are
|
||||
/// strips of items that appear on various UI surfaces in CmdPal, such as a
|
||||
/// toolbar. Each ICommandItem returned from this method will be treated as
|
||||
/// one atomic band by cmdpal.
|
||||
///
|
||||
/// If the command on an item here is a
|
||||
/// IListPage, then cmdpal will render all of the items on that page as one
|
||||
/// band. You can use this to create complex bands with multiple buttons.
|
||||
/// </summary>
|
||||
public virtual ICommandItem[]? GetDockBands()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is used to manually populate the WinRT type cache in CmdPal with
|
||||
/// any interfaces that might not follow a straight linear path of requires.
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// 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 Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for creating a band out of a set of items. This allows you to
|
||||
/// simply just instantiate a set of buttons as ListItems, then pass them in to
|
||||
/// this class to create a band from those items. For example:
|
||||
///
|
||||
/// ```cs
|
||||
/// var foo = new MyFooListItem();
|
||||
/// var bar = new MyBarListItem();
|
||||
/// var band = new WrappedDockItem([foo, bar], "com.me.myBand", "My cool desk band");
|
||||
/// ```
|
||||
/// </summary>
|
||||
public partial class WrappedDockItem : CommandItem
|
||||
{
|
||||
public override string Title => _itemTitle;
|
||||
|
||||
public override IIconInfo? Icon
|
||||
{
|
||||
get => _icon; set { _icon = value; }
|
||||
}
|
||||
|
||||
public override ICommand? Command => _backingList;
|
||||
|
||||
private readonly string _itemTitle;
|
||||
private readonly WrappedDockList _backingList;
|
||||
private IIconInfo? _icon;
|
||||
|
||||
public IListItem[] Items { get => _backingList.GetItems(); set => _backingList.SetItems(value); }
|
||||
|
||||
public WrappedDockItem(
|
||||
ICommand command,
|
||||
string displayTitle)
|
||||
{
|
||||
_backingList = new WrappedDockList(command);
|
||||
_itemTitle = string.IsNullOrEmpty(displayTitle) ? command.Name : displayTitle;
|
||||
_icon = command.Icon;
|
||||
}
|
||||
|
||||
// This was too much of a foot gun - we'd internally create a ListItem that
|
||||
// didn't bubble the prop change events back up. That was bad.
|
||||
// public WrappedDockItem(
|
||||
// ICommandItem item,
|
||||
// string id,
|
||||
// string displayTitle)
|
||||
// {
|
||||
// _backingList = new WrappedDockList(item, id);
|
||||
// _itemTitle = string.IsNullOrEmpty(displayTitle) ? item.Title : displayTitle;
|
||||
// _icon = item.Icon;
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WrappedDockItem"/> class.
|
||||
/// Create a new dock band for a set of list items
|
||||
/// </summary>
|
||||
public WrappedDockItem(
|
||||
IListItem[] items,
|
||||
string id,
|
||||
string displayTitle)
|
||||
{
|
||||
_backingList = new WrappedDockList(items, id, displayTitle);
|
||||
_itemTitle = displayTitle;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
// 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 Microsoft.CommandPalette.Extensions.Toolkit;
|
||||
|
||||
/// <summary>
|
||||
/// Helper class for a list page that just holds a set of items as a band.
|
||||
/// The page itself doesn't do anything interesting.
|
||||
/// </summary>
|
||||
internal sealed partial class WrappedDockList : ListPage
|
||||
{
|
||||
private string _id;
|
||||
|
||||
public override string Id => _id;
|
||||
|
||||
private List<IListItem> _items;
|
||||
|
||||
internal WrappedDockList(ICommand command)
|
||||
{
|
||||
_items = new() { new ListItem(command) };
|
||||
Name = command.Name;
|
||||
_id = command.Id;
|
||||
}
|
||||
|
||||
// Maybe revisit sometime.
|
||||
// The hard problem is that the wrapping item will not
|
||||
// listen for property changes on the inner item.
|
||||
// public WrappedDockList(ICommandItem item, string id)
|
||||
// {
|
||||
// var command = item.Command;
|
||||
// _items = new()
|
||||
// {
|
||||
// new ListItem(command)
|
||||
// {
|
||||
// Title = item.Title,
|
||||
// Subtitle = item.Subtitle,
|
||||
// Icon = item.Icon,
|
||||
// MoreCommands = item.MoreCommands,
|
||||
// },
|
||||
// };
|
||||
// Name = command.Name;
|
||||
// _id = string.IsNullOrEmpty(id) ? command.Id : id;
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="WrappedDockList"/> class.
|
||||
/// Create a new list page for the set of items provided.
|
||||
/// </summary>
|
||||
internal WrappedDockList(IListItem[] items, string id, string name)
|
||||
{
|
||||
_items = new(items);
|
||||
Name = name;
|
||||
_id = id;
|
||||
}
|
||||
|
||||
internal WrappedDockList(ICommand[] items, string id, string name)
|
||||
{
|
||||
_items = new();
|
||||
foreach (var item in items)
|
||||
{
|
||||
_items.Add(new ListItem(item));
|
||||
}
|
||||
|
||||
Name = name;
|
||||
_id = id;
|
||||
}
|
||||
|
||||
public override IListItem[] GetItems()
|
||||
{
|
||||
return _items.ToArray();
|
||||
}
|
||||
|
||||
internal void SetItems(IListItem[]? newItems)
|
||||
{
|
||||
if (newItems == null)
|
||||
{
|
||||
_items = [];
|
||||
RaiseItemsChanged(0);
|
||||
return;
|
||||
}
|
||||
|
||||
ListHelpers.InPlaceUpdateList(_items, newItems);
|
||||
RaiseItemsChanged(_items.Count);
|
||||
}
|
||||
}
|
||||
@@ -405,6 +405,11 @@ namespace Microsoft.CommandPalette.Extensions
|
||||
{
|
||||
Object[] GetApiExtensionStubs();
|
||||
};
|
||||
|
||||
|
||||
[contract(Microsoft.CommandPalette.Extensions.ExtensionsContract, 1)]
|
||||
interface ICommandProvider3 requires ICommandProvider2
|
||||
{
|
||||
ICommandItem[] GetDockBands();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user