Skip to content

Commit

Permalink
BarPlugin YAML config (#1050)
Browse files Browse the repository at this point in the history
- Added a declarative config for the BarPlugin.
- To improve testability, `BarComponent` is now an abstract record. This doesn't change the behavior of the bar.
- Added missing docs for the window backdrop
  • Loading branch information
dalyIsaac authored Oct 10, 2024
1 parent 4ee4586 commit 6aaeb1c
Show file tree
Hide file tree
Showing 24 changed files with 1,303 additions and 70 deletions.
23 changes: 23 additions & 0 deletions docs/configure/core/styling.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
# Styling

[!INCLUDE [Styling](../../_includes/core/styling.md)]

## Backdrops

Different Whim windows can support custom backdrops. They will generally be associated with a `backdrop` key in the YAML/JSON configuration. The following backdrops are available:

- `none`: No backdrop
- `acrylic`: An [acrylic backdrop](https://docs.microsoft.com/en-us/windows/apps/design/style/acrylic)
- `acrylic_thin`: A more transparent Acrylic backdrop - based on the Acrylic backdrop

| Type | Description | WinUI Documentation |
| -------------- | ----------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| `none` | No backdrop | N/A |
| `acrylic` | A translucent texture that blurs the content behind it. | [Acrylic material](https://docs.microsoft.com/en-us/windows/apps/design/style/acrylic) |
| `acrylic_thin` | A more transparent version of the Acrylic backdrop. | N/A |
| `mica` | An opaque, dynamic material that incorpoates theme and the desktop wallpaper. Mica has better performance than Acrylic. | [Mica material](https://learn.microsoft.com/en-us/windows/apps/design/style/mica) |
| `mica_alt` | A variant of Mica with stronger tinting of the user's background color. | [Mica alt material](https://learn.microsoft.com/en-us/windows/apps/design/style/mica) |

### Configuration

| Property | Description |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type` | The type of backdrop to use. |
| `always_show_backdrop` | By default, WinUI will disable the backdrop when the window loses focus. Whim overrides this setting. Set this to false to disable the backdrop when the window loses focus. |
85 changes: 82 additions & 3 deletions docs/configure/plugins/bar.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,86 @@
# Bar Plugin

👷🏗️🚧
The `BarPlugin` adds a configurable bar at the top of each monitor.

## Tree Layout
![Bar demo](../../images/bar-demo.png)

👷🏗️🚧
```yaml
plugins:
bar:
left_components:
entries:
- type: workspace_widget

center_components:
entries:
- type: focused_window_widget
shorten_title: true

right_components:
entries:
- type: battery_widget
- type: active_layout_widget
- type: date_time_widget
format: HH:mm:ss, dd MMM yyyy
- type: tree_layout_widget
```
## Configuration
| Property | Description |
| ------------------- | ------------------------------------------------------------------------------- |
| `is_enabled` | Whether the plugin is enabled |
| `height` | The height of the bar in pixels. |
| `backdrop` | The backdrop to use for the bar - see [Backdrops](../core/styling.md#backdrops) |
| `left_components` | The widgets to display on the left side of the bar. |
| `center_components` | The widgets to display in the center of the bar. |
| `right_components` | The widgets to display on the right side of the bar. |

## Components

The `left_components`, `center_components`, and `right_components` properties have lists of components under the `entries` key. Each component has a `type` key that specifies the type of widget to use. The following widgets are available:

- [Configuration](#configuration)
- [Components](#components)
- [Widgets](#widgets)
- [Active Layout Widget](#active-layout-widget)
- [Battery Widget](#battery-widget)
- [Date Time Widget](#date-time-widget)
- [Focused Window Widget](#focused-window-widget)
- [Workspace Widget](#workspace-widget)
- [Tree Layout Widget](#tree-layout-widget)

## Widgets

### Active Layout Widget

The `ActiveLayoutWidget` displays the name of the current layout.

### Battery Widget

The `BatteryWidget` displays the battery percentage and status.

### Date Time Widget

The `DateTimeWidget` displays the current date and time.

| Property | Description |
| ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `interval` | The interval in milliseconds to update the date and time. |
| `format` | The format to display the date and time in. For more, see [Custom date and time format strings](https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings) |

### Focused Window Widget

The `FocusedWindowWidget` displays the title of the focused window.

| Property | Description |
| --------------- | ------------------------------------------- |
| `shorten_title` | Whether to shorten the title of the window. |

### Workspace Widget

The `WorkspaceWidget` displays the name of the current workspace.

### Tree Layout Widget

The `TreeLayoutWidget` displays the direction to add windows in the tree layout engine on the current workspace. This will only show if the current layout in the workspace is a tree layout.
13 changes: 7 additions & 6 deletions docs/configure/plugins/command-palette.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,13 @@ plugins:
## Configuration
| Property | Description |
| -------------------- | -------------------------------------------------------------------------------- |
| `is_enabled` | Whether the plugin is enabled. Defaults to `true`. |
| `max_height_percent` | The maximum height of the command palette as a percentage of the monitor height. |
| `max_width_pixels` | The maximum width of the command palette in pixels. |
| `y_position_percent` | The y position of the command palette as a percentage of the monitor height. |
| Property | Description |
| -------------------- | -------------------------------------------------------------------------------------------- |
| `is_enabled` | Whether the plugin is enabled. Defaults to `true`. |
| `backdrop` | The backdrop to use for the command palette - see [Backdrops](../core/styling.md#backdrops). |
| `max_height_percent` | The maximum height of the command palette as a percentage of the monitor height. |
| `max_width_pixels` | The maximum width of the command palette in pixels. |
| `y_position_percent` | The y position of the command palette as a percentage of the monitor height. |

[!INCLUDE [Commands](../../_includes/plugins/command-palette.md)]

Expand Down
2 changes: 1 addition & 1 deletion docs/script/plugins/bar.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Bar Plugin

The <xref:Whim.Bar.BarPlugin> adds a configurable bar at the top of a screen.
The <xref:Whim.Bar.BarPlugin> adds a configurable bar at the top of each monitor.

![Bar demo](../../images/bar-demo.png)

Expand Down
15 changes: 11 additions & 4 deletions src/Whim.Bar/ActiveLayout/ActiveLayoutWidget.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,15 @@ public ActiveLayoutWidget(IContext config, IMonitor monitor)
/// <summary>
/// Creates a new bar component which contains the active layout widget.
/// </summary>
public static BarComponent CreateComponent()
{
return new BarComponent((context, monitor, window) => new ActiveLayoutWidget(context, monitor));
}
public static BarComponent CreateComponent() => new ActiveLayoutComponent();
}

/// <summary>
/// The bar component for the active layout widget.
/// </summary>
public record ActiveLayoutComponent : BarComponent
{
/// <inheritdoc/>
public override UserControl CreateWidget(IContext context, IMonitor monitor, Microsoft.UI.Xaml.Window window) =>
new ActiveLayoutWidget(context, monitor);
}
60 changes: 48 additions & 12 deletions src/Whim.Bar/BarConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,20 @@
namespace Whim.Bar;

/// <summary>
/// Delegate for creating a component.
/// A component will subscribe to <see cref="Microsoft.UI.Xaml.Window.Closed"/> if it has resources to dispose.
/// A component to display in the bar.
/// </summary>
public delegate UserControl BarComponent(IContext context, IMonitor monitor, Microsoft.UI.Xaml.Window window);
public abstract record BarComponent
{
/// <summary>
/// Delegate for creating a component.
/// A component will subscribe to <see cref="Microsoft.UI.Xaml.Window.Closed"/> if it has resources to dispose.
/// </summary>
/// <param name="context"></param>
/// <param name="monitor"></param>
/// <param name="window"></param>
/// <returns></returns>
public abstract UserControl CreateWidget(IContext context, IMonitor monitor, Microsoft.UI.Xaml.Window window);
}

/// <summary>
/// Configuration for the bar plugin.
Expand All @@ -21,9 +31,18 @@ namespace Whim.Bar;
/// <remarks>
/// Creates a new bar configuration.
/// </remarks>
/// <param name="leftComponents">The components to display on the left side of the bar.</param>
/// <param name="centerComponents">The components to display in the center of the bar.</param>
/// <param name="rightComponents">The components to display on the right side of the bar.</param>
/// <param name="leftComponents">
/// The components to display on the left side of the bar. Changes to this list will be respected until the
/// bar is initialized.
/// </param>
/// <param name="centerComponents">
/// The components to display in the center of the bar. Changes to this list will be respected until the
/// bar is initialized.
/// </param>
/// <param name="rightComponents">
/// The components to display on the right side of the bar. Changes to this list will be respected until the
/// bar is initialized.
/// </param>
public class BarConfig(
IList<BarComponent> leftComponents,
IList<BarComponent> centerComponents,
Expand All @@ -34,19 +53,25 @@ IList<BarComponent> rightComponents
public event PropertyChangedEventHandler? PropertyChanged;

/// <summary>
/// The components to display on the left side of the bar.
/// The components to display in the center of the bar. This will be set to the provided list, until
/// the bar is initialized.
/// </summary>
internal IList<BarComponent> LeftComponents = leftComponents;
public IReadOnlyList<BarComponent> LeftComponents { get; private set; } =
(IReadOnlyList<BarComponent>)leftComponents;

/// <summary>
/// The components to display in the center of the bar.
/// The components to display in the center of the bar. This will be set to the provided list, until
/// the bar is initialized.
/// </summary>
internal IList<BarComponent> CenterComponents = centerComponents;
public IReadOnlyList<BarComponent> CenterComponents { get; private set; } =
(IReadOnlyList<BarComponent>)centerComponents;

/// <summary>
/// The components to display on the right side of the bar.
/// The components to display in the center of the bar. This will be set to the provided list, until
/// the bar is initialized.
/// </summary>
internal IList<BarComponent> RightComponents = rightComponents;
public IReadOnlyList<BarComponent> RightComponents { get; private set; } =
(IReadOnlyList<BarComponent>)rightComponents;

private int _height = GetHeightFromResourceDictionary() ?? 30;

Expand Down Expand Up @@ -85,6 +110,17 @@ protected virtual void OnPropertyChanged(string propertyName)
/// </remarks>
public WindowBackdropConfig Backdrop { get; set; } = new(BackdropType.Mica, AlwaysShowBackdrop: true);

/// <summary>
/// Freezes the configuration, making it immutable.
/// </summary>
/// <returns></returns>
internal void Initialize()
{
LeftComponents = new List<BarComponent>(LeftComponents);
CenterComponents = new List<BarComponent>(CenterComponents);
RightComponents = new List<BarComponent>(RightComponents);
}

private static int? GetHeightFromResourceDictionary()
{
try
Expand Down
12 changes: 8 additions & 4 deletions src/Whim.Bar/BarPlugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ namespace Whim.Bar;
public class BarPlugin(IContext context, BarConfig barConfig) : IBarPlugin
{
private readonly IContext _context = context;
private readonly BarConfig _barConfig = barConfig;

private readonly Dictionary<IMonitor, BarWindow> _monitorBarMap = [];
private bool _disposedValue;
Expand All @@ -24,20 +23,25 @@ public class BarPlugin(IContext context, BarConfig barConfig) : IBarPlugin
/// </summary>
public string Name => "whim.bar";

/// <inheritdoc/>
public BarConfig Config => barConfig;

/// <inheritdoc />
public void PreInitialize()
{
_context.MonitorManager.MonitorsChanged += MonitorManager_MonitorsChanged;
_context.FilterManager.AddTitleMatchFilter("Whim Bar");
_context.WorkspaceManager.AddProxyLayoutEngine(layout => new BarLayoutEngine(_barConfig, layout));
_context.WorkspaceManager.AddProxyLayoutEngine(layout => new BarLayoutEngine(Config, layout));

Config.Initialize();
}

/// <inheritdoc />
public void PostInitialize()
{
foreach (IMonitor monitor in _context.MonitorManager)
{
BarWindow barWindow = new(_context, _barConfig, monitor);
BarWindow barWindow = new(_context, Config, monitor);
_monitorBarMap[monitor] = barWindow;
}

Expand All @@ -57,7 +61,7 @@ private void MonitorManager_MonitorsChanged(object? sender, MonitorsChangedEvent
// Add the new monitors
foreach (IMonitor monitor in e.AddedMonitors)
{
BarWindow barWindow = new(_context, _barConfig, monitor);
BarWindow barWindow = new(_context, Config, monitor);
_monitorBarMap[monitor] = barWindow;
}

Expand Down
8 changes: 5 additions & 3 deletions src/Whim.Bar/BarWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ public BarWindow(IContext context, BarConfig barConfig, IMonitor monitor)
_backdropController = new(this, barConfig.Backdrop);

// Set up the bar.
LeftPanel.Children.AddRange(_barConfig.LeftComponents.Select(c => c(_context, _monitor, this)));
CenterPanel.Children.AddRange(_barConfig.CenterComponents.Select(c => c(_context, _monitor, this)));
RightPanel.Children.AddRange(_barConfig.RightComponents.Select(c => c(_context, _monitor, this)));
LeftPanel.Children.AddRange(_barConfig.LeftComponents.Select(c => c.CreateWidget(_context, _monitor, this)));
CenterPanel.Children.AddRange(
_barConfig.CenterComponents.Select(c => c.CreateWidget(_context, _monitor, this))
);
RightPanel.Children.AddRange(_barConfig.RightComponents.Select(c => c.CreateWidget(_context, _monitor, this)));
}

internal void UpdateRect()
Expand Down
15 changes: 11 additions & 4 deletions src/Whim.Bar/Battery/BatteryWidget.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,15 @@ internal BatteryWidget(IContext context, IMonitor monitor)
/// <summary>
/// Creates a new bar component which contains the active layout widget.
/// </summary>
public static BarComponent CreateComponent()
{
return new BarComponent((context, monitor, window) => new BatteryWidget(context, monitor));
}
public static BarComponent CreateComponent() => new BatteryComponent();
}

/// <summary>
/// The bar component for the active layout widget.
/// </summary>
public record BatteryComponent : BarComponent
{
/// <inheritdoc/>
public override UserControl CreateWidget(IContext context, IMonitor monitor, Microsoft.UI.Xaml.Window window) =>
new BatteryWidget(context, monitor);
}
22 changes: 18 additions & 4 deletions src/Whim.Bar/DateTime/DateTimeWidget.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,22 @@ internal DateTimeWidget(int interval, string format)
/// <param name="interval"></param>
/// <param name="format"></param>
/// <returns></returns>
public static BarComponent CreateComponent(int interval = 100, string format = "HH:mm:ss dd-MMM-yyyy")
{
return new BarComponent((context, monitor, window) => new DateTimeWidget(interval, format));
}
public static BarComponent CreateComponent(int interval = 100, string format = "HH:mm:ss dd-MMM-yyyy") =>
new DateTimeComponent(interval, format);
}

/// <summary>
/// The bar component for the date time widget.
/// </summary>
/// <param name="IntervalMs">
/// The interval in milliseconds to update the date time.
/// </param>
/// <param name="Format">
/// The date time format. See <see href="https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings">Custom date and time format strings</see>.
/// </param>
public record DateTimeComponent(int IntervalMs, string Format) : BarComponent
{
/// <inheritdoc/>
public override UserControl CreateWidget(IContext context, IMonitor monitor, Microsoft.UI.Xaml.Window window) =>
new DateTimeWidget(IntervalMs, Format);
}
21 changes: 15 additions & 6 deletions src/Whim.Bar/FocusedWindow/FocusedWindowWidget.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,8 @@ internal FocusedWindowWidget(IContext context, IMonitor monitor, Func<IWindow, s
/// <param name="getTitle">
/// The function to get the title of the window. Defaults to <see cref="GetTitle(IWindow)"/>.
/// </param>
public static BarComponent CreateComponent(Func<IWindow, string>? getTitle = null)
{
return new BarComponent(
(context, monitor, window) => new FocusedWindowWidget(context, monitor, getTitle ?? GetTitle)
);
}
public static BarComponent CreateComponent(Func<IWindow, string>? getTitle = null) =>
new FocusedWindowComponent(getTitle);

/// <summary>
/// Gets the full title of the window.
Expand All @@ -59,3 +55,16 @@ public static string GetShortTitle(IWindow window)
/// <returns></returns>
public static string? GetProcessName(IWindow window) => window.ProcessFileName?.Replace(".exe", "");
}

/// <summary>
/// The bar component for the focused window widget.
/// </summary>
/// <param name="GetTitle">
/// The function to get the title of the window. Defaults to <see cref="FocusedWindowWidget.GetTitle(IWindow)"/>.
/// </param>
public record FocusedWindowComponent(Func<IWindow, string>? GetTitle) : BarComponent
{
/// <inheritdoc/>
public override UserControl CreateWidget(IContext context, IMonitor monitor, Microsoft.UI.Xaml.Window window) =>
new FocusedWindowWidget(context, monitor, GetTitle ?? FocusedWindowWidget.GetTitle);
}
Loading

0 comments on commit 6aaeb1c

Please sign in to comment.