Sorry: as I started implementing these I found more mistakes. Here are the UDOs updated:
opcode GridDraw, 0, iiiiii
iSize, iCols, iRows, iLeft, iTop, iId xin
iCount init 0
while iCount < iCols do
SCode sprintf "bounds(%d, %d, %d, %d) channel(\"g%dc%d\") range(0, %d, 0, 1, 1), filmstrip(\"vGridSlider%d.png\", %d, valueTextBox(\"0\"), popup(\"0\")", iCount*iSize+iLeft, iTop, iSize, iSize*iRows, iId, iCount+1, iRows-1, iRows, iRows
cabbageCreate "vslider", SCode
iCount+=1
od
SCode = sprintf("bounds(%d, %d, %d, %d), channel(\"overlay%d\"), colour(0, 0, 0, 100)", iLeft, iTop, iSize*iCols, iSize*iRows, iId)
cabbageCreate "image", SCode
endop
opcode GridCtl, 0, iiii
iSize, iCols, iRows, iId xin
kMouseDown chnget "MOUSE_DOWN_LEFT"
kMouseX chnget "MOUSE_X"
kMouseY chnget "MOUSE_Y"
SOverlay sprintf "overlay%d", iId
iOverlay[] cabbageGet SOverlay, "bounds"
iLeft = iOverlay[0]
iTop = iOverlay[1]
iWidth = iOverlay[2]
iHeight = iOverlay[3]
if (kMouseX > iLeft && kMouseX < iLeft+iWidth && kMouseY > iTop && kMouseY < iTop + iHeight) then
kColumn = int(((kMouseX - iLeft) / iSize) + 1)
kVal = int(((kMouseY - iTop) * -iRows / iHeight) + iRows)
if kMouseDown == 1 then
SChannel = sprintfk("g%dc%d", iId, kColumn)
cabbageSetValue SChannel, kVal
endif
endif
endop