# Write custom themes for HoustonPatchbay

## Introduction

This guide helps to write custom HoustonPatchbay patchbay themes, which are used by RaySession, Patchance and Patchichi.

A good practice is to modify an existing theme, starting from a light theme if you want to make a light theme, else starting from a dark theme.

Patchichi is the best tool to do that, because you can easily add on your patchbay all types of ports.

First right click on the patchbay, select Canvas Options, switch to the Theme tab, then select a theme and press duplicate, then edit, it will open your theme file with your default plain text reader (kate, gedit, …​).

Your theme should be located in:

`/home/user/.local/share/software/HoustonPatchbay/themes/MyTheme`

replace

- user with your user name

- software with the software you use in lower case (raysession, patchance or patchichi)

- My Theme with your theme name

You can now edit the theme.conf file to change the theme. When you save changes to the file, the theme is directly uploaded in the software, so you don’t need to restart the program to test the changes !

## directory tree

    / My Theme
    ↳ fonts
      ↳ font1.ttf
      ↳ font2.ttf
      ↳ ...
    ↳ icons
      ↳ monitor_capture.svg
      ↳ monitor_playback.svg
      ↳ ...
    ↳ images
      ↳ background.png
      ↳ background2.jpg
      ↳ ...
    ↳ theme.conf

Your theme directory must contain a file named `theme.conf` where all parameters are defined. Directories `fonts`, `icons` and `images` are optional.

### fonts

This folder contains .ttf or .otf font files. All .otf and .ttf files in this folder are installed by the software before loading the theme. Note that the font name that you will need in theme.conf is not necessary the file name.
You can use: `fc-scan --format "%{family}\n" FontFile.ttf` to know the font family name inside the file.

### icons

This folder contains icons for hardware, PulseAudio bridges and monitor boxes.

At this stage, only svg format is supported, the following file names can be used:

- hardware_capture.svg

- hardware_playback.svg

- hardware_grouped.svg

- hardware_midi.svg

- monitor_capture.svg

- monitor_playback.svg

### images

This folder contains images that you can use as background for the full scene or any widget (box, port or portgroup). A lot of image formats are supported.

## [aliases]

You can define in [aliases] block colors or numbers for faster general changes in other sections. For example, define midi to a color, and re-use midi for midi ports and midi lines. Note that aliases audio, midi, cv, alsa and video are now required for the view selector frame. Please affect them a color.

## [body]

in [body] block, define general colors and sizes for the scene.

Available parameters are:

- port-height : number

- port-grouped-width: number, minimum width of grouped ports

- box-spacing: number, spacing between boxes when they are moved around

- box-spacing-horizontal : number, horizontal spacing between boxes when they are moved around, if one of the boxes has ports on this side

- hardware-rack-width : number, size of the flycase decoration of hardware boxes

- monitor_color: color, color of the word Monitor in monitor boxes

- background : color, color of the scene background

- background-image : string, name of the image file to use as background, this file must be in the images folder of the theme folder

## specific blocks

We call here specific blocks all blocks defining theme except [body] and [aliases].

In each specific block, you can define the following settings:

- background : color

- background2 : color (optional, used to make a gradient from background to background2, may be unused with some widgets)

- background-image : image

- border-color : color

- border-mode: default or minimal can draw only few borders, as in Terminal theme

- border-radius : number between 0 and 50

- border-style :

  - solid, normal : normal border line

  - nopen, none : no border

  - dash : dashed line

  - dashdot : more dashed line

  - dashdotdot : more more dashed line

- border-width : number between 0 and 20

- font-name : string

- font-size : number between 1 and 200

- font-weight : number between 1 (very light) and 1000 (very bold). Or, with a large preference, it can also be:

  - thin : = 100

  - extralight : = 200

  - light : = 300

  - normal : = 400

  - medium : = 500

  - demibold : = 600

  - bold : = 700

  - extrabold : = 800

  - black : = 900

- text-color : color

- visible : boolean. Few blocks support this.

- drilled : boolean. Few blocks support this. If True, the parent widget is drilled. Useful only if background-color has transparency.

- grid-min-width : number, in grid block only

- grid-min-height : number, in grid block only

- inherits : only for portgroup block, can be port to inherit all port settings.

### margins

header and gui_button can also interpret some margin values: If the box has title on top:

- margin-bottom : number margin on bottom

- margin-top : number margin on top

- margin-sides: number margin on left and on right

If the box has title on side:

- margin-top-side : number margin on top and bottom

- margin-ports-side: number margin on the side which contains the ports

- margin-free-side : number margin on the opposite side of the ports

You can also apply in all cases

- margin : number. Set all margin-…​ attributes to value

### All specific blocks

The interpretable specific blocks are the following ones:

    box
    box.selected
    box.hardware
    box.hardware.selected
    box.monitor
    box.monitor.selected
    box.client
    box.client.selected
    box.client.with_gui
    box.client.with_gui.selected

    box_wrapper
    box_wrapper.selected
    box_wrapper.hardware
    box_wrapper.hardware.selected
    box_wrapper.monitor
    box_wrapper.monitor.selected
    box_wrapper.client
    box_wrapper.client.selected
    box_wrapper.client.with_gui
    box_wrapper.client.with_gui.selected

    box_header
    box_header.selected
    box_header.hardware
    box_header.hardware.selected
    box_header.monitor
    box_header.monitor.selected
    box_header.client
    box_header.client.selected
    box_header.client.with_gui
    box_header.client.with_gui.selected

    box_header_line
    box_header_line.selected
    box_header_line.hardware
    box_header_line.hardware.selected
    box_header_line.monitor
    box_header_line.monitor.selected
    box_header_line.client
    box_header_line.client.selected
    box_header_line.client.with_gui
    box_header_line.client.with_gui.selected

    box_shadow
    box_shadow.selected
    box_shadow.hardware
    box_shadow.hardware.selected
    box_shadow.monitor
    box_shadow.monitor.selected
    box_shadow.client
    box_shadow.client.selected
    box_shadow.client.with_gui
    box_shadow.client.with_gui.selected

    box_ports_border
    box_ports_border.selected
    box_ports_border.hardware
    box_ports_border.hardware.selected
    box_ports_border.monitor
    box_ports_border.monitor.selected
    box_ports_border.client
    box_ports_border.client.selected
    box_ports_border.client.with_gui
    box_ports_border.client.with_gui.selected

    port
    port.selected
    port.audio
    port.audio.selected
    port.midi
    port.midi.selected
    port.cv
    port.cv.selected

    portgroup
    portgroup.selected
    portgroup.audio
    portgroup.audio.selected
    portgroup.midi
    portgroup.midi.selected
    portgroup.cv
    portgroup.cv.selected

    line
    line.selected
    line.disconnecting
    line.audio
    line.audio.selected
    line.midi
    line.midi.selected

    rubberband

    gui_button
    gui_button.gui_hidden
    gui_button.gui_visible

    monitor_decoration
    monitor_decoration.selected

    hardware_rack
    hardware_rack.selected

Of course, you don’t need to specify all of themes. If in a block a setting is unspecified, the program will look into the parent block. For example, to know which are the theme settings of an audio port, the program will look for settings in this order

    port.audio
    port

Note that if the audio port is selected, it will check if "selected" block of the parent block exists and search inside before. The order of search will be:

    port.audio.selected
    port.audio
    port.selected
    port

### [Box]

In addition to all common block settings, a box block can also interpret the following settings:

- output-align: left or right, determines if the output ports names should be aligned on left or on right

- icon-size : number, default is 24

- port-in-offset: number, the horizontal offset of the input ports from the border of the box

- port-out-offset: number, the horizontal offset of the output ports from the border of the box

- port-offset: number, set port-in-offset and port-out-offset

- port-in-offset-mode : number, bore or none, determinates if the box should be bored with port-offset (for input ports)

- port-out-offset-mode : number, bore or none, determinates if the box should be bored with port-offset (for output ports)

- port-offset-mode : number, set port-in-offset-mode and port-out-offset-mode

- port-spacing : number, vertical spacing between ports (if they are not in the same portgroup)

- port-type-spacing: number, vertical spacing between ports of different type, in addition to port_spacing

The available Box Blocks are the following ones:

    box
    box.selected
    box.hardware
    box.hardware.selected
    box.monitor
    box.monitor.selected
    box.client
    box.client.selected

- hardware : boxes representing hardware physicals groups.

- monitor : boxes representing Monitors of hardware physicals groups (only for PipeWire)

- client : RaySession client boxes, if JACK client name follows the NSM rules.

### [wrapper]

wrapper is the little triangle used to wrap/unwrap boxes.
The available blocks are the same than for boxes:

    wrapper
    wrapper.selected
    wrapper.hardware
    wrapper.hardware.selected
    wrapper.monitor
    wrapper.monitor.selected
    wrapper.client
    wrapper.client.selected

### [header_line]

header_line represents lines at left and at right of a box title, if the box is larger than the title.
The available blocks are the same than for boxes:

    header_line
    header_line.selected
    header_line.hardware
    header_line.hardware.selected
    header_line.monitor
    header_line.monitor.selected
    header_line.client
    header_line.client.selected

### [port]

port is a named connection endpoint. They can be input or output ports. For coherence, you can’t change their shape, only colors and sizes.
The available port blocks are:

    port
    port.selected
    port.audio
    port.audio.selected
    port.midi
    port.midi.selected
    port.cv
    port.cv.selected

a CV port is a Control Voltage port. It works like an audio port, but it is not meant to be listened.

### [portgroup]

portgroup is a group of ports ! In most cases it is an audio stereo pair.
The available blocks are the same than for port.

    portgroup
    portgroup.selected
    portgroup.audio
    portgroup.audio.selected
    portgroup.midi
    portgroup.midi.selected
    portgroup.cv
    portgroup.cv.selected

That said, in Patchance or RaySession, portgroups exists only for regular audio ports (for the moment, but are midi or CV portgroups really needed ??).

### [line]

a line represents a connection between two ports. The available line blocks are:

    line
    line.selected
    line.disconnecting
    line.audio
    line.audio.selected
    line.midi
    line.midi.selected

line.disconnecting is the color of a line which will be disconnected if the user release the mouse button on the port or portgroup under the cursor. Please choose for this a color near but different from the [body] background-color.

### [rubberband]

rubberband is the rectangle of selection that you will see when you press mouse button in the background and drag the cursor to select multiple boxes. It doesn’t have child blocks.

### [gui_button]

gui_button is the rectangle under the box title drawn if the box belongs to a client capable to show/hide its GUI.
User will just have to double-click on this rectangle (or anywhere on the box) to toggle GUI visibility state.

Available blocks are:

    gui_button
    gui_button.gui_hidden
    gui_button.gui_visible

### [monitor_decoration]

monitor_decoration is the band on the left of a monitor box (only for PipeWire).
Available blocks are :

    monitor_decoration
    monitor_decoration.selected

monitor_decoration.selected is the decoration when the box is selected.

### [hardware_rack]

hardware_rack is the decoration that simulates a flycase rack around hardware boxes.
Available blocks are :

    hardware_rack
    hardware_rack.selected

hardware_rack.selected is the hardware_rack when the box is selected.

## Glossary

### color

color is specified with a string understandable by Qt QColor.

Examples:

- white

- red

- #DDD (each hexadecimal character specify a RGB channel, here a little gray)

- #A0A000 (each block of two hexadecimal character specify a RGB channel)

- #FF5050A0 (the first block of two specify alpha channel, nexts are for RGB channels)

alternatively you can write colors this way :

- rgb(255, 0, 0) (each RGB channel from 0 to 255, here red)

- rgba(255, 0, 0, 0.5) (each RGB channel from 0 to 255, and opacity from 0.0 to 1.0)

for convenience, you can quickly adjust color lightness and/or opacity. for example:

- `background=red * 0.8` will result in a slightly dark red.

- `background=red ** 0.8` will result in a red with an opacity at 80%.

- `background=#AFD755 * 1.2 ** 0.4`

spaces between color and number are required, number MUST be after color.

### boolean

boolean is True or False.

### number

number defines an integer or a float.

### image

image is a string. Its name must match with a file in `images` directory, in the theme folder.

for example, the following line:

    background-image=background.jpg

means that the background image of the object will be the image file `THEMES_PATH/theme_name/images/background.jpg`.

Important | a background-image is visible ONLY if background of the same section is a color with transparency. First, image is drawn, then background color is drawn above. This allows to adjust the color of image applying a color with transparency above, mainly for readability and for quick corrections.

### font

font is a string matching with a font family.

Example:
`text-color=Deja Vu Sans`

if the font exists in fonts dir, this will be chosen, else font will be found in system fonts.