Skip to content
Cabbage
Install

Widgets

ListBox

listBox creates a scrollable list of items which users can choose from. A single click highlights an item without sending anything to Csound. A double-click sends the index of the highlighted item to Csound on the widget’s channel.

listBox.csd
Download .csd
"active": true

Will deactivate a control if false is set (use 0/1 to update from Csound). Controls which are deactivated can still be updated from Csound. Any widget that has its active property set to false will allow all mouse-clicks to pass through it.

"automatable": true

Defaults to true. Determines if a widget is automatable by a host DAW. Automatable widgets show up as plug-in parameters in the host. Non-automatable widgets can still communicate with Csound but are not accessible by the host. Note that hosts don't allow this parameter to change dynamically. If you change this setting, the plugin will need to be reloaded.

"bounds": {"left":0, "top":0, "width":100, "height":100}

Integer values that set position and size on screen(in pixels).

"channels": [
{
"id": "channelName",
"label": { "name": "Channel Name", "prefix": "", "suffix": "" },
"event": "valueChanged",
"type": "number",
"range": {"min":0, "max":100, "defaultValue":0, "skew":1, "increment":0.1}
}
]

In Cabbage 3, widgets use an array of channels instead of a single channel string. Each channel object includes an id that defines a unique channel name. Widgets in Cabbage 3 can have any number of channels attached to them. An optional label object controls how the parameter appears in DAW parameter editors and automation lanes; if omitted, the id is used. An optional event property specifies the type of interaction. A range object can define the minimum, maximum, and default values, along with the skew and step increment. The type is set to number by default. Each widget sets its own type, number or string. A "string" channel carries text (readable with the string variant of cabbageGetValue), persists through session saves, and is excluded from DAW automation. See Persisting Custom UI State.

Channel label: DAW display name

The label object separates the internal channel identifier from the display name shown in DAWs, and allows a prefix and suffix to be appended to the parameter's value string in the DAW. This is useful when you want short, code-friendly channel IDs (e.g., hrm1, hrm2) while showing descriptive names in the DAW (e.g., Harmonic 1, Harmonic 2). Csound code always uses the id for channel access via cabbageGetValue and cabbageSetValue.

FieldDescription
name Human-readable parameter name shown in the DAW (required if using label)
prefix String prepended to the value in the DAW's value display (optional)
suffix String appended to the value in the DAW's value display (optional)

If range is omitted, it defaults to a range from 0 to 1, with increments of 0.001 for widgets that use drag events (e.g., sliders, XY pads) and 1 for widgets that use click or toggle events (e.g., buttons, checkboxes).

Note on increment parameter behavior:

The increment parameter quantizes all values sent to Csound channels, ensuring they snap to the specified step size. For example, with increment: 0.1, values will be rounded to 0.0, 0.1, 0.2, etc. before reaching Csound.

The DAW host automation has additional constraints:

  • increment >= 1.0: The host will display discrete integer steps (e.g., move from 1 to 2 to 3, etc.) in its native controls, and enforce these steps during automation.
  • increment < 1.0: The host displays a continuous slider.

Cabbage always quantizes values internally before sending to Csound.

Supported event types:

EventDescription
valueChanged (default)Tracks simple value changes
mousePressLeftTracks presses of left mouse button
mousePressRightTracks presses of right mouse button
mousePressMiddleTracks presses of middle mouse button
mouseMoveXTracks movement along X axis.
mouseMoveYTracks movement along Y axis.
mouseDragXTracks movement along X axis with mouse pressed
mouseDragYTracks movement along Y axis with mouse pressed
mouseInside Returns max when any mouse button is within the bounds of the widget, min if outside.

The listBox channel only sends its value on double-click, so each trigger corresponds to a deliberate user selection.

"id": "widgetId"

This optional channel can be used to define a top-level line of communication between the instrument’s UI and Csound. It is reserved for UI updates only. If omitted, it defaults to the first id from the channels array. Its primary purpose is to help produce clearer code, especially for widgets with multiple channels.

"items": ["item1", "item2", ...]

A list of items that will populate the comboBox/listBox or optionButton. Each item has a corresponding index value. The first item when selected will send a 0, the second item a 1, the third a 2 etc. If this identifier is left out default values of "Item 1", "Item 2", "Item 3", "Item 4" and "Item 5" will be used.

"persistence": {
"preset": true,
"session": true
}

Controls whether a widget's state is saved in DAW presets and Csound session files. Both properties default to true.

  • preset: When true, the widget's current value/state is included when using Csound's cabbageSaveState opcode to save preset data. Set to false for widgets that should not persist in Csound preset files (e.g., widgets that load presets).
  • session: When true, the widget's state is included when the DAW saves a preset. Set to false for widgets that should not have their values loaded/saved when a DAW session loads (e.g., widgets that load presets).

Auto-cascade behavior: If you set preset to false without explicitly setting session, the system automatically sets session to false as well. This prevents state from being saved anywhere unless explicitly requested.

"populate": {
"directories": [""],
"fileType": "",
"fullFileAndPath": false,
"order": "date",
"labelWhenEmpty": "No Files",
"defaultLabel": ""
}

Sets the type of file to search for, and the directories to look in. You can specify multiple file types by using the following pattern *.txt;*.csv;*.dat.

Because the web-based frontend has no access to the local file system, file scanning is performed by the backend. A static populate block in your CSD is scanned automatically when the instrument loads (and again on every recompile), so in most cases you only need to declare the directories up front. Setting populate.directories at runtime from your Csound code remains useful when the target directory must be chosen dynamically, or to guarantee a correct absolute path — for example, the following Csound code sets the target directory to that of the current .csd file:

cabbageSet("presetCombo", "populate.directories", chnget:S("CSD_PATH"))

Relative directory paths resolve against the Cabbage application folder rather than the folder holding your .csd, which is why the absolute CSD_PATH pattern above is recommended whenever files must be found reliably.

The items can be ordered by "date", "size" or "alphabetically". "defaultLabel" sets the initial text when the combobox first appears. If it's empty, the first item on the list will appear by default.

"visible": true

A value of true will cause the widget to become invisible (use 0/1 to update from Csound). Widgets have their visibility set to true by default.

"zIndex": 1

Sets the stacking order of the widget. Widgets with higher zIndex values will appear in front of widgets with lower values. Default is 1.

"style": {
"opacity": 1,
"borderRadius": 2,
"borderWidth": 1,
"borderColor": "#222222",
"backgroundColor": "#ffffff",
"fontFamily": "Verdana",
"fontSize": "auto",
"fontColor": "#000000",
"highlightColor": "#dddddd",
"textAlign": "left"
},
  • Colors accept named CSS colors, hex (e.g., #RRGGBB or #RRGGBBAA), or rgb/rgba strings.
  • fontSize: "auto" scales the text to fill the row height; set a number (px) to fix it.
  • highlightColor is the background of the currently selected row; backgroundColor is the background of all other rows.
  • textAlign controls the alignment of item text within each row ("left", "center" or "right").

The listBox returns the index of the double-clicked item along with a k-rate trigger value. The trigger value will be 1 for one k-cycle when an item is double-clicked, then return to 0. Read it with the CabbageNumTrig struct form of cabbageGetValue:

sel:CabbageNumTrig = cabbageGetValue("note")
if sel.trig == 1 then
event("i", "Tone", 0, 1, sel.val)
endif

Set the channel "type" to "string" to receive the double-clicked item text instead of its index:

"channels": [{"id": "presetCombo", "range": {}, "type": "string"}]
sel:CabbageStrTrig = cabbageGetValue("presetCombo")
if sel.trig == 1 then
event("i", "LOAD_PRESET", 0, .1)
endif

A string channel carries text, persists through session saves, and is excluded from DAW automation.

listBox.csd
<Cabbage>
{
"pluginId" : "def1",
"enableDevTools": true,
"channelConfig" : [ {"name": "0 in 2 out", "ins": "0", "outs": "2"} ],
"widgets" : [
{ "type": "form", "caption": "Listbox Example", "size": {"width": 600, "height": 170} },
{
"type" : "label",
"style" : {"fontColor": "#d1d1d1"},
"channels": [ {"id": "info", "event": "valueChanged"} ],
"bounds" : {"left": 0, "top": 10, "width": 600, "height": 40},
"label" : {"text": "Single-click an item to highlight it. Double-click an item to send it to Csound."}
},
{
"type" : "listBox",
"items" : ["A3", "C4", "D4", "E4", "G4", "A4"],
"bounds" : {"left": 12, "top": 56, "width": 174, "height": 102},
"channels": [
{ "id": "note", "range": {"max": 5} }
],
"style" : {"borderRadius": 5, "fontSize": 8}
},
{
"type" : "textEditor",
"bounds" : {"left": 190, "top": 56, "width": 401, "height": 100},
"channels": [
{ "id": "infoText", "range": {"defaultValue": 0, "increment": 0.001, "max": 1, "min": 0, "skew": 1} }
],
"readOnly": 1,
"wrap" : 1,
"style" : {"fontSize": 12},
"label" : {"text": "Double-click a note..."}
}
]
}
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d
</CsOptions>
<CsInstruments>
; Initialize the global variables.
ksmps = 32
nchnls = 2
0dbfs = 1
; Rory Walsh 2021
;
; License: CC0 1.0 Universal
; You can copy, modify, and distribute this file,
; even for commercial purposes, all without asking permission.
instr 1
sel:CabbageNumTrig = cabbageGetValue("note")
; The listbox only sends its value on double-click, so each
; trigger corresponds to a deliberate user selection.
if sel.trig == 1 then
event("i", "Tone", 0, 1, sel.val)
endif
endin
instr Tone
SNotes[] = fillarray("A3", "C4", "D4", "E4", "G4", "A4")
iFreqs[] = fillarray(220, 261.63, 293.66, 329.63, 392, 440)
iIdx = int(p4)
iIdx = (iIdx < 0 || iIdx > 5 ? 0 : iIdx)
cabbageSet("infoText", "label.text", sprintf("You double-clicked %s", SNotes[iIdx]))
aEnv = madsr(0.01, 0.1, 0.7, 0.4)
a1 = oscili(0.3*aEnv, iFreqs[iIdx])
outs(a1, a1)
endin
</CsInstruments>
<CsScore>
;starts instrument 1 and runs it for a week
i1 0 z
</CsScore>
</CsoundSynthesizer>