Table of Contents

Class UIHost

Namespace
PluginUI
Assembly
PluginUI.dll

Hosts a tree of UIElements in a Win32 child window rendered with Direct2D. The same class serves plug-in editors (child of the DAW window) and standalone applications (child of a StandaloneWindow).

public sealed class UIHost : IDisposable
Inheritance
UIHost
Implements
Inherited Members

Examples

A standalone application (in a plug-in, PluginEditorView creates and attaches the host):

StandaloneWindow.EnablePerMonitorDpiAwareness();
var root = new Canvas();
root.Add(new Knob(new LocalParameter("Drive", 0, 10, 2)) { Label = "DRIVE", Left = 20, Top = 20, Width = 72, Height = 96 });
var host = new UIHost(root, new Size(320, 200), SizingMode.ScaleToFit)
{
    Theme = Theme.Dark.WithAccent(Color.FromRgb(0xFFB74D)),
    MinSize = new Size(240, 150),
};
return new StandaloneWindow(host, "Drive").Run();

Remarks

Lifecycle: create with a root and a design size → AttachToParent(nint, bool) (window created) → SetPixelSize(int, int) / SetDpiScale(float) as the container dictates → Detach() (window destroyed) → Dispose(). A host can be attached again after a detach.

The container owns the message loop: no Application.Run inside a plug-in.

Constructors

UIHost(UIElement, Size, SizingMode)

Creates a host.

public UIHost(UIElement root, Size designSize, SizingMode sizing = SizingMode.Fixed)

Parameters

root UIElement

Root element (often a Canvas or a Grid).

designSize Size

Logical size of the editor at 100 %.

sizing SizingMode

Sizing behavior.

Properties

Animator

Animation engine.

public Animator Animator { get; }

Property Value

Animator

BackgroundColor

Background color cleared before drawing (defaults to the theme background).

public Color? BackgroundColor { get; set; }

Property Value

Color?

CapturedElement

Element holding the mouse capture.

public UIElement? CapturedElement { get; }

Property Value

UIElement

DefaultLanguage

Language used by every host whose Language is null (default Auto: the Windows display language of the user). Set it once at startup, e.g. from a plugin setting.

public static string DefaultLanguage { get; set; }

Property Value

string

DesignSize

Logical size of the design at 100 %.

public Size DesignSize { get; set; }

Property Value

Size

DpiScale

System/host content scale (1 = 96 DPI).

public float DpiScale { get; }

Property Value

float

FocusedElement

Element with keyboard focus.

public UIElement? FocusedElement { get; }

Property Value

UIElement

FollowWindowDpi

Follows DPI changes of the parent window (WM_DPICHANGED_AFTERPARENT). Plug-in adapters turn this off when the DAW drives the scale explicitly (VST3 setContentScaleFactor).

public bool FollowWindowDpi { get; set; }

Property Value

bool

FrameInterval

Interval of the frame timer (animations, meters). Default 16 ms (~60 fps).

public TimeSpan FrameInterval { get; set; }

Property Value

TimeSpan

HasKeyboardFocus

true while the host window has the Win32 keyboard focus.

public bool HasKeyboardFocus { get; }

Property Value

bool

HoveredElement

Deepest element under the mouse.

public UIElement? HoveredElement { get; }

Property Value

UIElement

IsAttached

true while a native window exists.

public bool IsAttached { get; }

Property Value

bool

IsDragging

true during an internal drag-and-drop operation.

public bool IsDragging { get; }

Property Value

bool

IsLiveEditEnabled

Live layout editing (Ctrl+Shift+E): select elements, move and resize them with the mouse or the keyboard, then copy the resulting C# code (Ctrl+C) back into the editor source.

public bool IsLiveEditEnabled { get; set; }

Property Value

bool

IsResizable

true if the container may let the user resize the editor.

public bool IsResizable { get; }

Property Value

bool

KeepAspectRatio

Keeps the design aspect ratio when resizing in ScaleToFit.

public bool KeepAspectRatio { get; set; }

Property Value

bool

Language

Language of the texts PluginUI displays in this host (dialog buttons, preset menu, tooltips…): Auto, English, French or any code registered with Register(string, UIStrings); null = DefaultLanguage. Numbers always use a decimal point, whatever the language (see InvariantNumber).

public string? Language { get; set; }

Property Value

string

LiveEditShortcutEnabled

Enables the Ctrl+Shift+E live-edit shortcut.

public bool LiveEditShortcutEnabled { get; set; }

Property Value

bool

LiveEditor

Live editor (created on first use).

public LiveEditor LiveEditor { get; }

Property Value

LiveEditor

LogicalSize

Logical size the root is laid out in.

public Size LogicalSize { get; }

Property Value

Size

MaxSize

Maximum logical size (resizable modes).

public Size MaxSize { get; set; }

Property Value

Size

MidiLearn

MIDI learn back-end (null = no MIDI learn). When set, the right-click menu of controls bound to a parameter offers "MIDI Learn" / "Forget MIDI assignment", merged into the DAW's parameter menu by plug-in adapters.

public IMidiLearnService? MidiLearn { get; set; }

Property Value

IMidiLearnService

MinSize

Minimum logical size (resizable modes).

public Size MinSize { get; set; }

Property Value

Size

ModalBackdrop

Color drawn over the UI behind a modal popup.

public Color ModalBackdrop { get; set; }

Property Value

Color

MousePosition

Last mouse position in DIPs.

public Point MousePosition { get; }

Property Value

Point

ParameterContextMenuRequested

Called on right click over a control bound to a parameter (when the control has no own context menu): lets the plug-in adapter show the DAW's parameter menu. Return true if handled.

public Func<IParameter, Point, bool>? ParameterContextMenuRequested { get; set; }

Property Value

Func<IParameter, Point, bool>

PixelSize

Current size in physical pixels.

public (int Width, int Height) PixelSize { get; }

Property Value

(int Width, int Height)

Popups

Open popups, bottom to top.

public IReadOnlyList<Popup> Popups { get; }

Property Value

IReadOnlyList<Popup>

PreferredPixelSize

Pixel size the editor would like (design × DPI × zoom).

public (int Width, int Height) PreferredPixelSize { get; }

Property Value

(int Width, int Height)

ResizeRequestHandler

Asked by the host when it needs a new pixel size (zoom, DPI change, CornerResizer). Return true if the container accepted (it then calls SetPixelSize(int, int)). When null, the host resizes its own window.

public Func<int, int, bool>? ResizeRequestHandler { get; set; }

Property Value

Func<int, int, bool>

Root

Root element.

public UIElement Root { get; set; }

Property Value

UIElement

Scale

Pixels per DIP currently applied.

public float Scale { get; }

Property Value

float

Remarks

In ScaleToFit the design is scaled uniformly to fit both dimensions (a window with another aspect ratio leaves an empty band on the right or at the bottom).

ShowFocusRings

Draws keyboard focus rings (turned on by keyboard navigation, off by mouse clicks).

public bool ShowFocusRings { get; set; }

Property Value

bool

Sizing

Sizing behavior.

public SizingMode Sizing { get; set; }

Property Value

SizingMode

Strings

Texts in effect: the table assigned here, or the table of Language. Assign a custom UIStrings to override some texts for this host only; assign null to go back to the language table.

[AllowNull]
public UIStrings Strings { get; set; }

Property Value

UIStrings

TakeFocusOnClick

Gives the host window the keyboard focus on every click (standalone apps); plug-ins only take it for text input.

public bool TakeFocusOnClick { get; set; }

Property Value

bool

TextMeasurer

Text measurement (device-accurate once a renderer exists).

public ITextMeasurer TextMeasurer { get; }

Property Value

ITextMeasurer

Theme

Theme of every element in this host.

public Theme Theme { get; set; }

Property Value

Theme

ToolTipDelay

Delay before a tooltip appears.

public TimeSpan ToolTipDelay { get; set; }

Property Value

TimeSpan

UnhandledException

Called when an exception is caught at a native boundary (window procedure, timers, posted actions). Exceptions never propagate into the host application; by default they are written to the debug output.

public static Action<Exception, string>? UnhandledException { get; set; }

Property Value

Action<Exception, string>

UseNativeMenus

Shows menus with the native Win32 menu instead of the custom-drawn popup.

public bool UseNativeMenus { get; set; }

Property Value

bool

WindowHandle

Native window handle (0 when detached).

public nint WindowHandle { get; }

Property Value

nint

Zoom

User zoom factor (Fixed and Relayout modes); changing it asks the container to resize.

public float Zoom { get; set; }

Property Value

float

Methods

AddTicker(ITickable)

Registers a per-frame callback (meters, scopes, custom animations). It runs on the UI thread until Tick(double) returns false or RemoveTicker(ITickable) is called.

public void AddTicker(ITickable ticker)

Parameters

ticker ITickable

AttachToParent(nint, bool)

Creates the child window inside parentHwnd at the current pixel size.

public void AttachToParent(nint parentHwnd, bool detectDpi = true)

Parameters

parentHwnd nint

Parent window (DAW editor frame, standalone window...).

detectDpi bool

Reads the DPI of the parent and applies it (when the container does not provide a scale).

BeginDrag(UIElement, object, Action<bool>?)

Starts an internal drag-and-drop (call while the mouse button is held, e.g. from OnMouseMove(MouseEventArgs)). Elements under the pointer receive OnDragOver(DragEventArgs), the accepting one OnDrop(DragEventArgs).

public void BeginDrag(UIElement source, object data, Action<bool>? completed = null)

Parameters

source UIElement

Element starting the drag.

data object

Payload.

completed Action<bool>

Called with true if dropped on an accepting element.

BeginTextEdit(Rect, string, Action<string>, Action?, TextStyle?, Func<char, bool>?)

Shows a text box over bounds for in-place editing. Enter or a click outside commits, Escape cancels.

public TextEditPopup BeginTextEdit(Rect bounds, string text, Action<string> commit, Action? cancel = null, TextStyle? style = null, Func<char, bool>? filter = null)

Parameters

bounds Rect

Area covered by the editor (DIP).

text string

Initial text (selected).

commit Action<string>

Called with the final text when the user commits.

cancel Action

Called when the user cancels (Escape), or null.

style TextStyle

Text style, or null for the theme's default.

filter Func<char, bool>

Character filter (return false to reject a typed character), or null.

Returns

TextEditPopup

The popup, already shown.

Exceptions

ArgumentNullException

commit is null.

BeginTextEdit(Rect, string, Func<string, bool>, Action?, TextStyle?, Func<char, bool>?)

Shows a text box over bounds for in-place editing with validation: when tryCommit returns false the editor stays open, its frame turns red (IsInvalid) and the text is selected for correction. Escape cancels; a click outside commits a valid text and cancels an invalid one.

public TextEditPopup BeginTextEdit(Rect bounds, string text, Func<string, bool> tryCommit, Action? cancel = null, TextStyle? style = null, Func<char, bool>? filter = null)

Parameters

bounds Rect

Area covered by the editor (DIP).

text string

Initial text (selected).

tryCommit Func<string, bool>

Applies the text and returns true, or returns false to reject it.

cancel Action

Called when the edit is cancelled, or null.

style TextStyle

Text style, or null for the theme's default.

filter Func<char, bool>

Character filter (return false to reject a typed character), or null.

Returns

TextEditPopup

The popup, already shown.

Examples

host.BeginTextEdit(area, "0.5", text =>
{
    if (!InvariantNumber.TryParse(text, out double v)) return false; // "0,5" is refused
    myValue = v;
    return true;
});

Exceptions

ArgumentNullException

tryCommit is null.

CaptureMouse(UIElement)

Gives the mouse capture to element.

public void CaptureMouse(UIElement element)

Parameters

element UIElement

CheckAccess()

true on the UI thread (or before the window exists).

public bool CheckAccess()

Returns

bool

CloseAllPopups()

Closes every popup.

public void CloseAllPopups()

ClosePopup(Popup)

Closes a popup and every popup opened after it (sub-menus).

public void ClosePopup(Popup popup)

Parameters

popup Popup

ConstrainPixelSize(ref int, ref int)

Clamps a proposed pixel size to the min/max size and aspect ratio.

public void ConstrainPixelSize(ref int pixelWidth, ref int pixelHeight)

Parameters

pixelWidth int
pixelHeight int

Detach()

Destroys the native window (the element tree is kept; the host can be attached again).

public void Detach()

DipToScreen(Point)

Converts a point in host DIPs to screen pixels (native menus, external windows).

public (int X, int Y) DipToScreen(Point point)

Parameters

point Point

Returns

(int Width, int Height)

DispatchKeyDown(KeyEventArgs)

Dispatches a key press. Returns true if handled (unhandled keys go back to the DAW).

public bool DispatchKeyDown(KeyEventArgs e)

Parameters

e KeyEventArgs

Returns

bool

DispatchKeyUp(KeyEventArgs)

Dispatches a key release.

public bool DispatchKeyUp(KeyEventArgs e)

Parameters

e KeyEventArgs

Returns

bool

DispatchMouseDown(Point, MouseButton, int, ModifierKeys)

Dispatches a mouse button press (DIPs).

public void DispatchMouseDown(Point p, MouseButton button, int clickCount, ModifierKeys modifiers)

Parameters

p Point
button MouseButton
clickCount int
modifiers ModifierKeys

DispatchMouseMove(Point, ModifierKeys)

Dispatches a mouse move (DIPs). Public for custom containers and tests.

public void DispatchMouseMove(Point p, ModifierKeys modifiers)

Parameters

p Point
modifiers ModifierKeys

DispatchMouseUp(Point, MouseButton, ModifierKeys)

Dispatches a mouse button release (DIPs).

public void DispatchMouseUp(Point p, MouseButton button, ModifierKeys modifiers)

Parameters

p Point
button MouseButton
modifiers ModifierKeys

DispatchTextInput(string)

Dispatches typed text to the focused element.

public bool DispatchTextInput(string text)

Parameters

text string

Returns

bool

DispatchWheel(Point, float, bool, ModifierKeys)

Dispatches a wheel event (DIPs, notches). Returns true if an element handled it.

public bool DispatchWheel(Point p, float notches, bool horizontal, ModifierKeys modifiers)

Parameters

p Point
notches float
horizontal bool
modifiers ModifierKeys

Returns

bool

DispatchWheel(float)

Wheel at the last known mouse position (VST3 onWheel).

public bool DispatchWheel(float notches)

Parameters

notches float

Returns

bool

Dispose()

Detaches (if needed) and releases every resource.

public void Dispose()

EnsureFrameTimer()

Starts the frame timer if it is not running (called by the animator and tickers).

public void EnsureFrameTimer()

EvictImage(object)

Releases the GPU copy of an image or SVG this host has drawn (it is rebuilt if drawn again). Device copies are cached per host until the window closes: evict images you replace dynamically (album art, waveforms...).

public void EvictImage(object imageOrSvg)

Parameters

imageOrSvg object

Focus(UIElement?)

Moves the keyboard focus (null clears it). Returns false if the element cannot take it.

public bool Focus(UIElement? element)

Parameters

element UIElement

Returns

bool

GetParameterMenuItems(IParameter)

Menu entries PluginUI adds for a parameter (MIDI learn commands when MidiLearn is set), in the interface language. Plug-in adapters append them to the DAW's parameter menu.

public IReadOnlyList<MenuItem> GetParameterMenuItems(IParameter parameter)

Parameters

parameter IParameter

The parameter of the control that was right-clicked.

Returns

IReadOnlyList<MenuItem>

The entries (possibly empty).

HideToolTip()

Hides the tooltip.

public void HideToolTip()

HideValueBubble(UIElement)

Hides the value bubble if owner shows it.

public void HideValueBubble(UIElement owner)

Parameters

owner UIElement

HitAt(Point)

Deepest element under a point, popups included (null over a modal backdrop).

public UIElement? HitAt(Point point)

Parameters

point Point

Returns

UIElement

Invalidate()

Requests a repaint (coalesced into one WM_PAINT).

public void Invalidate()

InvalidateLayout()

Requests a layout pass and a repaint.

public void InvalidateLayout()

MoveFocus(bool)

Moves the focus to the next (or previous) focusable element (Tab navigation).

public bool MoveFocus(bool forward)

Parameters

forward bool

Returns

bool

Post(Action)

Runs action on the UI thread (thread-safe). Actions posted while detached run after the next attach.

public void Post(Action action)

Parameters

action Action

ProcessPostedActions()

Runs the posted actions now (UI thread; used by tests and offscreen hosts).

public void ProcessPostedActions()

ReleaseMouseCapture()

Releases the mouse capture (no OnCaptureLost() callback: voluntary release).

public void ReleaseMouseCapture()

RemoveTicker(ITickable)

Unregisters a per-frame callback.

public void RemoveTicker(ITickable ticker)

Parameters

ticker ITickable

RenderToPng(string, float)

Renders the UI offscreen and saves it as PNG (documentation, previews, automated tests). Works whether or not the host is attached to a window.

public void RenderToPng(string path, float scale = 1)

Parameters

path string

Destination file.

scale float

Pixels per DIP of the image.

RequestKeyboardFocus()

Gives the Win32 keyboard focus to the host window (text input, standalone apps).

public void RequestKeyboardFocus()

RequestResize(int, int)

Requests a new pixel size from the container.

public bool RequestResize(int pixelWidth, int pixelHeight)

Parameters

pixelWidth int
pixelHeight int

Returns

bool

SetDpiScale(float)

Sets the content scale (DPI / 96). The host asks the container for the matching pixel size through RequestResize(int, int) (in ScaleToFit the current size is scaled proportionally).

public void SetDpiScale(float scale)

Parameters

scale float

SetPixelSize(int, int)

Sets the pixel size (called by the container: VST3 onSize, window WM_SIZE...).

public void SetPixelSize(int pixelWidth, int pixelHeight)

Parameters

pixelWidth int
pixelHeight int

ShowMenu(IList<MenuItem>, Point)

Shows a menu at a point (context menus).

public void ShowMenu(IList<MenuItem> items, Point at)

Parameters

items IList<MenuItem>
at Point

ShowMenu(IList<MenuItem>, Rect, PopupPlacement, float, Action?)

Shows a menu next to an anchor rectangle (drop-downs, menu buttons).

public void ShowMenu(IList<MenuItem> items, Rect anchor, PopupPlacement placement = PopupPlacement.Below, float minWidth = 0, Action? closed = null)

Parameters

items IList<MenuItem>

Entries.

anchor Rect

Anchor in host DIPs.

placement PopupPlacement

Placement relative to the anchor.

minWidth float

Minimum width (e.g. the drop-down width).

closed Action

Called when the menu closes (chosen or dismissed).

ShowPopup(Popup)

Shows a popup above the UI (it is laid out at the next frame).

public void ShowPopup(Popup popup)

Parameters

popup Popup

ShowToolTip(string, Rect, UIElement?)

Shows a tooltip immediately at an anchor (custom tooltips; normal tooltips use ToolTip).

public void ShowToolTip(string text, Rect anchor, UIElement? owner = null)

Parameters

text string
anchor Rect
owner UIElement

ShowValueBubble(UIElement, string)

Shows (or updates) the value bubble above owner.

public void ShowValueBubble(UIElement owner, string text)

Parameters

owner UIElement
text string

StepFrame(double)

Advances animations and tickers by dt seconds (driven by the frame timer; public for tests and snapshots).

public void StepFrame(double dt)

Parameters

dt double

UpdateLayout()

Runs the layout pass now if needed.

public void UpdateLayout()

Events

Attached

Raised after the native window was created.

public event Action<UIHost>? Attached

Event Type

Action<UIHost>

Detaching

Raised before the native window is destroyed.

public event Action<UIHost>? Detaching

Event Type

Action<UIHost>

FilesDropped

Raised when files are dropped where no element accepted them.

public event Action<UIHost, FilesDroppedEventArgs>? FilesDropped

Event Type

Action<UIHost, FilesDroppedEventArgs>

FocusChanged

Raised when the keyboard focus moves.

public event Action<UIHost, UIElement?>? FocusChanged

Event Type

Action<UIHost, UIElement>

FrameTick

Raised on every frame-timer tick while animations or tickers are active.

public event Action<UIHost, double>? FrameTick

Event Type

Action<UIHost, double>

KeyboardFocusChanged

Raised when the host window gains or loses the Win32 keyboard focus.

public event Action<UIHost, bool>? KeyboardFocusChanged

Event Type

Action<UIHost, bool>

LiveEditChanged

Raised when live edit mode is turned on or off.

public event Action<UIHost, bool>? LiveEditChanged

Event Type

Action<UIHost, bool>

PreviewKeyDown

Raised before a key is dispatched to the focused element (global shortcuts). Set Handled to stop it.

public event Action<UIHost, KeyEventArgs>? PreviewKeyDown

Event Type

Action<UIHost, KeyEventArgs>