I’m changing Knob from DSP code this way, as suggested by @Vorticotime ago:
paramQuantity->setValue(newParamValue);
It seems work pretty well, except I could “move” the knob from GUI (even if that has not effect, since the next process() will overwrite the value changed from GUI).
So basically its a weird behaviour on UX side; I’d like to totally avoid draggable knob while its piloted by dsp code. Is there a way to do this? ParamWidget seems doesn’t have a “isDragging” bool which I can atomically set to false.
If I place the knob as child of that UnclickableLayer, I can’t cover the knob with some layer/color on top… (such as opacity layer which grey out the knob color below it)
It can be “ok” for this case: I don’t want any action over the knob.
Probably I need somethings like this instead TransparentWidget > knob widget > custom grey widget, where grey is on top of knob. Like adding a “text” over a knob…
But as said above, not sure why covering a TransparentWidget won’t do the task
Because covering a widget does not make that widget a child, it just means that the two widgets draw themselves in the same place.
Normally when an event occurs on a widget, it will optionally do something with it, then it will propagate that event on to its children, and then each child widget will do that same thing. Therefore the event travels down the tree. (or I guess up the tree depending on which way you look at it)
The TransparentWidget only blocks events that occur upon it, from being propagated to its own children.
So to make use of this you must do TransparentWidget->addChild(OtherWidget), and then OtherWidget will not get events that occur on TransparentWidget
That child widget does not have to be the Knob itself, it could be any other widget that has the Knob as one of its children. Because the child does not get the event, it has no way to pass it on. So all widgets on the tree below the TransparentWidget will not get events from the TransparentWidget parent…
IOW You have to create a derived class. It cannot be acheived by simply positioning existing widgets.
The derived class can layer a transparent widget, but then it must switch that child in and out or do sizing trickery for the enabled/disabled states. The alternative is to override input handling to filter propagation based on the enabled state.
It makes sense to provide a visual indication of disabled state, otherwise the knob is just mysteriously dead.
Also consider providing tip text to indicate when it’s disabled and why.
Maybe better to simply not use a param’s value in yor DSP code. If you want to freeze a value, then just reset it to that value whenever you’re processing control input.
Well, if you want something that you can use for any control, then like Paul said, you are going to have to roll your own. I would think that most devs would end up doing this eventually…
There are any number of ways to achieve what you want, and probably most will have both Pros and Cons.
The reason I suggested using the speed parameter is, when I want to create something complex, I follow a simple process:
actually start making it
make it do the thing that you want
test it and see if it fulfills your initial requirements
only then, clean up and optimize
Otherwise I typically find myself wasting time on something that didn’t need to block me.
In my plugin, the original modules all have a context menu function that switches the knobs from being attenuvertors to simply following the CV input, which makes the knobs move by themselves. I think is is similar to your issue? But I don’t disable the knobs from user input, I can imagine many a UXer telling me that is bad design…
Anyway, you probably need to write your own custom Knob struct (or possibly some sort of decorator style struct that you can compose with any GUI control) to achieve what you want, but maybe just use the speed param for now to see if it actually fulfills your requirements?
Tried your suggestion about TransparentWidget “before” the param. Here’s my attempt:
ParamWidget *myParam = getParam(16); // pointer to the knob
myParam->addChildBottom(new UnclickableLayer(myParam->box.size));
I can clearly see UnclickableLayer before the param, but I can still move knob and such, so it seems is passing event as well even if the parent is a TransparentWidget.
Surge has deactivatble knobs. (Hook up an audio input to the input of the ring modulator in 2.2.2 and the frequency and detune knobs draw no handle, no ring, and respond to no mouse events).