= Write custom themes for *HoustonPatchbay*
:toc: left
:toclevels: 2
:imagesdir: images
:stylesheet: patchbay_manual.css

== 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]
=== 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.

[#body]
== [body]

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

Available parameters are:

* *port-height* : <<number>>
* *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
* *magnet* : <<number>>, if the distance between borders of glued boxes is lower or equal to this value, boxes will be aligned
* *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>>
* *text-color* : <<color>>
* *font-name* : string
* *font-size* : <<number>> between 1 and 200
* *font-width* : <<number>> between 0 (very light) and 99 (very bold). alternatively, it can also be _normal_ or _bold_.
* *border-color* : <<color>>
* *border-width* : <<number>> between 0 and 20
* *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

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_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_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_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

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 this 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:

* *port_in_offset* : the horizontal offset of the input ports from the border of the box
* *port_out_offset* : the horizontal offset of the output ports from the border of the box
* *port_spacing* : vertical spacing between ports (if they are not in the same portgroup)
* *port_type_spacing* : 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

_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.

[#number]
=== number

_number_ defines an integer or a float.

[#image]
=== 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

_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.
