Any way to save plugin UI resize factor as a Parameter? Yes - one approach here

I know we can save the plugin UI size by overriding SerializeState/UnSerializeState with Serialize/UnSerializeEditorState functions but that approach has to be implemented when the plugin is first released. If we try to add it later it will break backwards compatibility with saved projects, user presets, etc., due to the inserted chunk data. We could add it at the end of the parameter chunk data but that would prohibit any new parameters from being added in any future plugin updates.

So, is there any way the plugin UI size can be saved as a parameter - that can be added to the existing plugin parameter list after-the-fact like any other new control? I understand It would have to be called from mMakeGraphicsFunc or mLayoutFunc - but is it possible to do this, e.g., with a custom parameter function?

Not sure if it’s a good idea to save the size as a parameter since it IMHO it’s nothing that needs to be reported to the host in that meaning. Though i don’t see a technical reason why you can’t do it.
However i’d strongly advise to change your un/serializing in that way that you put a version number in front of all other arbitrary data. Reading the version upfront of all other date makes it possible to do individual data handling depending on which data to be expected.

1 Like

The purpose would be that it recalls the last UI size as set by the user just as it recalls all other control settings last touched by the user.

Yes, that would be good - in hindsight. Unfortunately once a plugin is released and users have created projects and presets with it you can’t change anything in the chunk format or it will break backward compatibility.

All that said, I have found a way to save the UI size as a plugin parameter and I will share it here for anyone who’s interested. The advantage of this approach is that it can be added to any existing plugin without breaking backwards compatibility - just as adding any other new control parameter to the end of the parameter list.

I started by declaring a global variable to store the resize value as float PluginUISize (initialized to 1.0) along with a new plugin parameter kPluginUISize that I added to the bottom of the parameter list.

I establish the new parameter and hide it from automation like this (0.67 to 1.5 is my resize range):

GetParam(kPlugUIScale)->InitDouble(“UI Scale”, PlugUIScale, 0.67, 1.5, 0.01, “”, IParam::kFlagCannotAutomate);

and then added the associated call to OnParamChange() that retrieves the value saved in the parameter chunk:

case kPlugUIScale:
    {PlugUIScale = GetParam(kPlugUIScale)->Value();}
break;

I then added this line to the very bottom of mLayoutFunc that redraws the UI to the saved parameter size each time the UI is opened:

pGraphics->Resize(PLUG_WIDTH, PLUG_HEIGHT, PlugUIScale, true);

Finally, the current UI rescale size is retrieved and saved to the kPluginUIScale parameter by calling this in OnIdle():

if (GetUI() && PlugScale != GetUI()->GetDrawScale()) PlugUIScale = GetUI()->GetDrawScale(), GetParam(kPlugUIScale)->Set(PlugUIScale);

I tried adding the above “Get & Save Current Size” code to OnUIClose() but I found out that if the plugin UI is open when the DAW is closed OnUIClose doesn’t get called - so that didn’t always work. Repeatedly checking the plugin size in OnIdle() is inefficient but I found no other way to capture the current resize value.

Anyhow, this is unusual but it works. It saves the plugin UI size in the DAW project as well as when copies of the plugin are moved to other tracks, etc. It basically does the same thing saving the Editor State does in this regard but adding it does not mess up any existing chunk data - so it’s backwards compatibile.

That’s not quite true - you just need a way of differentiating different versions - such as by chunk size, or by adding a string/byte sequence at the end that couldn’t occur any other way. It’s very easy if you don’t need the compatibility of being able to open new presets on old versions of the plugin and a little bit trickier if you need that to work, but it is possible to devise a way to make sure all scenarios work.

Anything you do (such as the much more convoluted solution above that I wouldn’t advise) is adding to the saved chunks, so there’s no way to avoid that - the thing is to do so sensibly and so as to allow you to detect which preset version you are dealing with. For backwards compatibility you need to make sure you don’t alter anything within the number of bytes that your plugin is currently writing.

You don’t have to recommend what I did - I just posted it here for anyone who may want to try it.

The fact is I have achieved the result I wanted using simple, existing IPlug functions - and without breaking backwards compatibility.

You 're talking about some custom chunk reading/writing code here. Where are the instructions on how to implement this?

It’s not that simple. You also cannot place anything new in front of it - like the SaveEditorState example - as that throws off the entire sequence of bytes previously saved that will then load into the wrong parameters.

IMO, it should be a standard parameter. It’s a user control like any other user control.

You override UnserializeState() and SerializeState(). Or do you mean how do you read and write to chunks? You can look at IGEditorDelegate::UnserializeEditorSize() and IPluginBase::UnserializeParams() (plus the serialising equivalents) to see how chunk reading and writing can be done. The number of bytes might also vary per format, but there are definitely ways to be able to ensure compatibility forwards and back, although they might take a bit of thought and testing with both plugin versions to get right.

You don’t have to recommend what I did - I just posted it here for anyone who may want to try it.

I suppose the bit that seems most unnecessary is the way you set the parameter - surely there is some kind of GUI interaction to set the scale in your plugin - can you not get that to set the parameter? If you are using a corner resizer then I’d suggest customising that in some way.

It’s not that simple. You also cannot place anything new in front of it - like the SaveEditorState example - as that throws off the entire sequence of bytes previously saved that will then load into the wrong parameters.

Apologies if my text on this was a bit terse - I meant to imply that you have to leave the first X bytes alone - you can do what you wish after that. I’m aware that you can’t place anything at the top if backwards compatibility is a concern.

Thank you, and yes those methods are what I was referring to in the OP here. We have to be very careful when changing anything in the chunk formatting if we already have published plugins in service. I worked with these methods for awhile and ended up going back to the iPlug default handling but I will take another look when I have time to really study it.

In the meantime…

What I have done above may seem convoluted but is really quite simple.

Yes, I am using the corner resizer but I have found no means to retrieve it’s current value without modifying that code in some way (with a new “GetSize()” function, etc.). So I retrieve it using the existing GetDrawScale() which I call in On Idle().

I then save that value to a global variable which is stored in the plugin chunk data as a parameter. Every time the UI is opened it resizes the UI to the scale of that size parameter using pGraphics->Resize(PLUG_WIDTH, PLUG_HEIGHT, PlugUIScale, true).

This approach does the exact same thing SerializeEditorState state does but it does so as a plugin parameter and not as a separate chunk section.

Again, the advantage of this approach is the UI size is being saved as a simple plugin parameter along with the other plugin parameters. I don’t need to override anything or mess with custom chunk read/write functions.

And it’s backwards compatible when added to the end of the parameter list. If at some later time I decide I don’t want that function I can just disable the code for it without messing with any chunk data.

We have to be VERY careful when changing anything in the chunk formatting if we already have published plugins in service

Agreed - you have to be careful but it is possible to devise read/write schemes to do what you want. Effectively what you are doing above is just writing an extra value to the end of your chunk, which won’t be read by old plugin versions, and when the new version reads old chunks it only reads what is available in terms of size. However, there are better schemes that also give you more control to change chunk data in future. It is hard to retrofit these things, so it may make sense to make this step as soon as possible. Perhaps this isn’t something for you current plugins, but might be worth considering for newer ones to give you more flexibility in future.

Yes, I am using the corner resizer but I have found no means to retrieve it’s current value without modifying that code in some way (with a new “GetSize()” function, etc

You would need to customise the resize, but this can be done with inheritance, and then you use the version of AttachCornerResizer that allows you to pass in your own resizer control. That’s the pattern I personally think would be best (that control would then be directly linked to your parameter).

If at some later I decide I don’t want that function I can just disable the code for it that, again, does not require messing with any chunk data.

It depends on what you disable and then what you add next - if you remove the parameter but then add a different new one you’ll run into compatibility issues.

No, of course it won’t be read by older plugins. “Backwards compatible” means that NEW plugin versions can correctly load OLD plugin version data (saved in DAW projects by previous versions of the plugin) - which it does when you add a parameter at the end of the list.

Anyhow, no need to belabor this. I answered my own question here with working code.

Some people use screwdrivers to open paint cans. That may not be the right tool for the job but it works and, for me, that’s all that matters. :slightly_smiling_face: