Cabbage Logo
Back to Cabbage Site

New Cabbage widget opcodes

Fantastic! All works… actually better then expected :smiley:
Thank you so much! So happy cooking with fresh cabbage :yum:

1 Like

So, I’m wondering, was one who has only used the old way for a short time, I was wondering if it is as simple as replacing “chnget/set” with their Cabbage equivalent? I’m sure there’s other things I will learn as I go, but can I just start off with replacing the new calls for the old?

Also, I like being able to encapsulate chucks of the gui code within a group object or an image, mostly so I can show and hide them as a group. So, is there anyway to use “cabbageCreate” to add widgets to groups?

If you’re going to use cabbageCreate, you don’t really need groups. You can just manage the components from the Csound side.

Making one call to hide/show everything is much more reliable than a bunch to hide and show and all of them… I’m pretty sure I’ll stick with creating them in Cabbage…

This is true. I will see about adding the use of groups with cabbageCreate. That would be nice.

You can now use the parent() identifier to specify which widget is another’s widget’s parent, for example:

<Cabbage>
form caption("Untitled") size(400, 300), guiMode("queue"), colour(58, 110, 182), pluginId("def1")
button bounds(180, 30, 80, 40), channel("toggle"), value(1)
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d --midi-key=4 --midi-velocity-amp=5
</CsOptions>
<CsInstruments>

ksmps = 32
nchnls = 2
0dbfs = 1

instr 1
    cabbageCreate "image bounds(0, 0, 100, 100), channel(\"image1\")"
    cabbageCreate "rslider bounds(10, 10, 100, 100), channel(\"slider1\"), parent(\"image1\")"
    kToggle, kTrig cabbageGetValue "toggle"
    cabbageSet kTrig, "image1", "visible", kToggle
endin

We got this feature for free as parent() was already used by Cabbage, but until now it was only ever used internally. I’ve only tested briefly, but it seems to work nicely.

This is awesome, Rory! My project will be creating lots of rows and columns of widgets. I could also see the possibility now of building plugins that can implement their own orchestras (within the knowledge of the user), we can create scores on the fly, and now we can build the gui in real-time.

Why do we need Cabbage again?

1 Like

I’m trying to access rslider limits (min, max) with cabbageGet. While kArray[] cabbageGet "slider", "bounds" works, kArray[] cabbageGet "slider", "range" doesn’t. Is it possible and which identifier should be used?

Ah, try ‘min’, or ‘max’. I don’t think I added support for array output from range. I can do so, but not till later today.

No hurry!

Neither “min” nor “max” get anything (at i- or k-rate). Getting the range would be very useful, e.g. for randomization.

btw. it seems that one has to specify cabbageGetValue:i(...) when reading at init time only. On the other hand chnget() seems to work without the rate specifier (at least for the init pass). It makes sense to use “:i”, so it seems confusing on the Csound side rather then on the Cabbage side. Maybe you have a comment on this? Thanks!

I think chnget defaults to i-time. so you don’t have to use the identifier. But I always recommend using the rate specifier regardless as it’s make things easier to read.

Correct that combobox items names cannot be altered using cabbageSet?

cabbageSet "SynthMode2", {{ items("FM","AM") }}

This only works for combobox that are set to channelType(“string”), i.e, they are not automatable. A combobox is like a slider, in that its range cannot be modified without breaking the host.

got it. ok, i think i can work with that… thanks.

I thought I had this with strget/set. Sorry the String type widgets always trip me up… is there a way to get an index still or store the string somehow to compare it to an ivar?

Yes, but because I neglected to add the the option of passing arrays to cabbageSet it is a little long winded. We also have to write our own IndexOf UDO for finding the index of a string within an array. Nevertheless, here is an example that lets users populate a combobox with text they type into a texteditor. It will also give you the correct index whenever the combobox is updated or changed.

<Cabbage>
form caption("Untitled") size(400, 300), guiMode("queue") pluginId("def1")
combobox bounds(26, 74, 143, 20) channel("combo1"), channelType("string") items("AM", "FM", "PM", "LMN"), value("AM")
texteditor bounds(26, 38, 142, 30) channel("texteditor1")
</Cabbage>
<CsoundSynthesizer>
<CsOptions>
-n -d -+rtmidi=NULL -M0 -m0d 
</CsOptions>
<CsInstruments>
; Initialize the global variables. 
ksmps = 32
nchnls = 2
0dbfs = 1


opcode IndexOf, k,SS[]

    SString, SStrings[] xin
    kCount = 0
    kIndex init 0
    kSize  = lenarray:k(SStrings)
    
    while kCount < kSize do
        if strcmpk(SString, SStrings[kCount]) == 0 then
            kIndex = kCount
        endif
        kCount +=1
    od

    xout kIndex
    
endop

instr 1

    SNewItem, kNewItemTrig cabbageGetValue "texteditor1"
    SCurrentItems[] cabbageGet "combo1", "text"
    
    if kNewItemTrig == 1 then
        event "i", "UpdateCombo", 0, 0.01 
    endif

    SCombo, kComboTrig cabbageGetValue "combo1"
    printf SCombo, kComboTrig
    printarray SCurrentItems, kComboTrig
    printk2 IndexOf(SCombo, SCurrentItems) 

endin

instr UpdateCombo
        
    SItem cabbageGetValue "texteditor1"
    SCurrentItems[] cabbageGet "combo1", "text"
    iNewArraySize = lenarray(SCurrentItems)+1
        
    SNewList init "items("
    iIndex = 0
    while iIndex < iNewArraySize-1 do
        SNewList strcat SNewList, strcat("\"", strcat(SCurrentItems[iIndex], "\", "))
        iIndex += 1
    od
        
    SNewList strcat SNewList, strcat("\"", strcat(SItem, "\")")) 
        
    ;we only need to do this when the instrument is released...
    cabbageSet release(), "combo1", SNewList
    cabbageSet release(), "combo1", strcat("value(\"", strcat(SItem, "\")"))


endin

</CsInstruments>
<CsScore>
;causes Csound to run for about 7000 years...
f0 z
;starts instrument 1 and runs it for a week
i1 0 [60*60*24*7] 
</CsScore>
</CsoundSynthesizer>

</CsInstruments>
<CsScore>
;causes Csound to run for about 7000 years...
f0 z
;starts instrument 1 and runs it for a week
i1 0 [60*60*24*7] 
</CsScore>
</CsoundSynthesizer>

Thanks Rory - it’s a bit of a workaround I was hoping I wouldn’t have to do…

Is there a way to simply compare the string in the combobox to a value for a conditional operation?
Something like this - but that works correctly - assuming the strset strings are the same as the combobox strings

if (chnget:S("ComboBoxString") == strget(1)) then
        ivar = 1
    elseif (chnget:S("ComboBoxString") == strget(2)) then
        ivar = 2
    else
        ivar = 3
    endif

I know this is sort of a Csound 101 question but it has forever evaded me why we cannot simply compare string values. I feel like I’m overthinking this whole thing though…

Is there no way you can put all those strget strings into an array? That’s really the simplest way I can think of doing it. Csound doesn’t have switch statements, that would make things a little cleaner.

Another note about the code above, it uses the text() identifier to grab the items. items() doesn’t actually work in this context. I need to fix that.

Just wanted to remind you of this. In 2.7.2,
iArr[] cabbageGet "...", "bounds"
works but
iArr[] cabbageGet "...", "range"
does not. I’d like to get the min and max values.

1 Like

Setting a widget value with cabbageSet updates the widget display of the value but the value isn’t sent to the instrument?

cabbageSetValue works as expected for this, so I assume it’s by design? If so, just curious why both functions weren’t wrapped up in cabbageSet.