Skip to content

2 Button configuration

Deulfi edited this page Oct 7, 2026 · 6 revisions

Buttons are defined in ucm.conf as button1 … button15 (15 slots, gaps allowed). Each button is a name followed by comma-separated states; each state is a name, then @, then key=value fields separated by :.

# conf format: one line, states separated by commas, fields by @/:
button1=example,state_1@icon=list_alt:badge=1:active=true:tooltip=Files:command=script-message-to uosc open-file,state_2@icon=folder_open:tooltip=File Dialog:command=script-message-to uosc show-in-directory

The same button, pushed from another script, looks like a compact JSON table (see Script messages):

local button = {
    state_1 = {
        icon = "list_alt", badge = "1", active = true,
        tooltip = "Files",
        command = "script-message-to uosc open-file",
    },
    state_2 = {
        icon = "folder_open",
        tooltip = "File Dialog",
        command = "script-message-to uosc show-in-directory",
    },
}
mp.commandv('script-message-to', 'ucm', 'set-button', 'example', mp.utils.format_json(button))

You can name states anything — state_1 / state_2 is just a convention (numbers are easy to keep in mind).

Buttons are referenced in uosc.conf with button:<name>:

controls=button:alt_control_items,button:alt_control_loop,gap,fullscreen,gap,button:alt_format,gap,<video>button:alt_resolution

Fields

All fields are optional; a state inherits missing fields from the button's default state (see Fill-up).

Field Meaning
icon Material Design icon name (picker)
badge badge text; keep it short (use gap in uosc.conf to fix spacing)
active makes the button active (white background) when its value is true
tooltip hover text
command command(s) executed on press; command1;command2;... — passed through to uosc
hide hides the button (useful when you want to unhide it later via script)

Field values and coercion

badge

  • UCM_NIL or {} → nil (badge hidden — explicit nil intent, survives fill-up)
  • any other string is kept as literal badge text — including "false", "0", ""
  • automatically hidden when empty after substitution (e.g. ?(f) with no file loaded)

active

  • "true" / true → active; "false" / false → inactive
  • other values are checked against active_truthy_values (anything not in the list = inactive)
  • a [[property]] reference makes the button active while the property is truthy
  • a [[property??value]] reference makes the button active while the property equals value

hide

  • "true" / true → hidden; "false" / false → visible; other values preserved

Fill-up (state inheritance)

The most common button is one where several states all look the same but do different things. With fill-up you write the shared fields once (in the default state) and each extra state only names the field that changes — usually just the command:

# same icon + tooltip across all three states; each extra state is only a command
state_1=icon=skip_next:tooltip=Jump:command=add 0
state_2=command=add 5
state_3=command=add 30

state_2 and state_3 don't repeat the icon or tooltip — they inherit them from state_1 (the default state). That's the whole point: change the icon once and all three states follow, instead of editing three copies. Without inheritance you'd write the full button per state:

state_1=icon=skip_next:tooltip=Jump:command=add 0
state_2=icon=skip_next:tooltip=Jump:command=add 5
state_3=icon=skip_next:tooltip=Jump:command=add 30

So inheritance keeps each state short enough to read at a glance, and the shared look lives in one place.

A few rules:

  • A state inherits from the button's default state (the one mapped to default in state_map; without a state_map, the first state of the first button).
  • Scalars are copied by value — states don't share references.
  • To clear a field in a non-default state, set it explicitly to UCM_NIL / {} (for badge) — omission means "inherit".
  • Buttons pushed via set-button are deep-copied, so the sending script's payload tables are never mutated.

Global options

The script-level options (state_map, state_cycle_map, revert_delay, …) configure ucm as a whole, not one button — see Global configuration.

Notes

  • Fields are separated by :, but the parser only splits at : followed by a known field name — commands containing colons (ports, UUIDs, wasapi/{…}) are safe.
  • Buttons already have a default command fallback: states without a command get command=noop, so pressing them is a no-op ping instead of an undefined message.

Clone this wiki locally