Skip to content
Michael Palmos edited this page Aug 14, 2022 · 17 revisions

Most wired configuration works in terms of blocks. Each notification is comprised of a tree structure of blocks, where each block represents a visual part of the notification.

Each block has 6 properties, 5 of which are mandatory:

Mandatory

Property Description
name A user defined name.
parent The name of the block that should be this block's parent.
hook Represents where this block should be joined to the parent block.
parent_anchor: Where to attach on the parent (TL, MT, TR, MR, BR, MB, BL, ML).
self_anchor: Where to attach on this block (TL, MT, TR, MR, BR, MB, BL, ML).
offset An x, y offset applied to the block position post-hook.
params Decides which type of block this should be. See the sidebar for block types.

Optional

Property Description
render_criteria A criteria for when this block should be drawn.
A block will draw if at least one of the criteria matches, or if render_criteria is empty.
See below for more information.
render_anti_criteria A criteria for when this block should not be drawn.
A block will not draw if at least one of the criteria matches.
See below for more information.

A basic layout configuration could consist of as little as 3 blocks:

  • A NotificationBlock, the base block for all notifications, which configures properties such as the notification background and its position.
  • Two TextBlocks: one for the summary text and one for the body text.
layout_blocks: [
    // Base block -- all layouts must have this.
    (
        name: "root",
        parent: "",
        hook: Hook(parent_anchor: TL, self_anchor: TL),
        offset: Vec2(x: 7.0, y: 7.0),
        params: NotificationBlock(( ... )),
    ),

    // Summary block.
    (
        name: "summary",
        parent: "root",
        hook: Hook(parent_anchor: TL, self_anchor: TL),
        offset: Vec2(x: 0.0, y: 0.0),
        params: TextBlock((
            text: "%s",
            ...
        )),
    ),

    // Body block.
    (
        name: "body",
        parent: "summary",
        hook: Hook(parent_anchor: MR, self_anchor: ML),
        offset: Vec2(x: 0.0, y: 0.0),
        params: TextBlock((
            text: "%b",
            ...
        ))
    ),
]

basic layout

So we have the root NotificationBlock which has a child TextBlock which has a child TextBlock:

  • NotificationBlock (hooked to monitor top left)
    • TextBlock (summary) (hooked to NotificationBlock top left)
      • TextBlock (body) (hooked to TextBlock middle right)

We can position blocks pretty intuitively by just hooking things together. This also allows us to have variable sized blocks, and most of the time, we don't even need to mess with offsets -- for spacing, most blocks have a padding setting, which does what it says.

Also note that we can use the self_anchor property to change which part of the block gets anchored to the parent_anchor. For example, we can use (parent_anchor: MR, self_anchor: ML) to vertically center this block to the right of the parent.


Real example, and the debug option

Let's take a look at a real notification with a more complete config unabridged version here, with the debug option enabled:

layout_blocks: [
    (
        name: "root",
        parent: "",
        hook: Hook(parent_anchor: TL, self_anchor: TL),
        offset: Vec2(x: 7.0, y: 7.0),
        params: NotificationBlock((
            border_width: 3.0,
            gap: Vec2(x: 0.0, y: 8.0),
            ...
        )),
    ),

    (
        name: "image",
        parent: "root",
        hook: Hook(parent_anchor: TL, self_anchor: TL),
        offset: Vec2(x: 0.0, y: 0.0),
        params: ImageBlock((
            image_type: App,
            padding: Padding(left: 20.0, right: 20.0, top: 20.0, bottom: 20.0),
            ...
        )),
    ),

    (
        name: "summary",
        parent: "image",
        hook: Hook(parent_anchor: TR, self_anchor: TL),
        offset: Vec2(x: 0.0, y: 0.0),
        params: TextBlock((
            text: "%s",
            font: "Arial 30",
            color: Color(r: 0.92157, g: 0.858824, b: 0.698039, a: 1.0),
            padding: Padding(left: 20.0, right: 20.0, top: 20.0, bottom: 20.0),
            ...
        )),
    ),

    (
        name: "body",
        parent: "summary",
        hook: Hook(parent_anchor: BL, self_anchor: TL),
        offset: Vec2(x: 10.0, y: 0.0),
        // This block is only rendered when both a Summary and a Body field exist in the notification.
        render_criteria: [Summary, Body],
        params: ScrollingTextBlock((
            text: "%b",
            font: "Arial 30",
            color: Color(r: 0.92157, g: 0.858824, b: 0.698039, a: 1.0),
            padding: Padding(left: 20, right: 20.0, top: 20.0, bottom: 20.0),
            ...
        )),
    ),
],

real notify debug

Green borders represent padded layout blocks, and red borders represent unpadded layout blocks.

The structure is as follows:

  • NotificationBlock (hooked to monitor top left)
    • ImageBlock (hooked to NotificationBlock top left)
      • TextBlock (summary) (hooked to ImageBlock top right)
        • TextBlock (body) (hooked to TextBlock (summary) bottom left)

Having not explained offset, I've added one to TextBlock (body) just to show what that might look like.


Render Criteria (and render-anti criteria)

Wired has support for logically deciding on which blocks to use at runtime depending on information about the notification. Check out the Render Criteria page for more information.