In the attached script (photo), WidgetValuechanged is calling Function HighLightWidget and trying to pass it a Widget Name by reference. GP_Script says, no - you can’t do that and gives me a syntax error, “Argument type mismatch”. I understand this because I am passing a literal (EG: “D101”). How can I pass a dereference or pointer to a Widget?
GP Script is not C - there is no “exposed” concept of pointers or dereferences.
The error message is correct and is telling you that you are trying to pass a variable of type String to a system function that wants a variable of type Widget
There are multiple issues with this script.
If you look at the system function documentation, those functions (SetWidgetFillColor, etc), are looking for widget variables, (e.g, your D101, D102) but you’re passing strings to those functions
You have not declared the variable i that you are using in the for loop of OnWidgetValueChanged callback.
Later in that same function, you are using capital I in the array index
When you fix all those things, it will compile (I know, I tried it )
It might by the case you cannot add widgets to a dynamic array, but you definitely can create a static array of widgets.
One caveat: you cannot use the object-like coding style with arrays: widgetArr[0].SetWidgetValue(0.5) might compile, but, if I recall correctly, won’t work.
SetWidgetValue(widgetArr[0], 0.5) compiles and works.
Yes, that’s also in the next update — however, one must be very careful about this kind of thing. There is currently no way to provide programmatic feedback as to whether it worked or not since the save itself must be done asynchronously
Maybe you could take the ‘cookie’ approach: the save function returns a handle-like value that can be used in a complementary function that returns the result (success, error, still_saving, bad_cookie) of that particular save. That function could be GetSaveGPPresetResult(cookie : int) returns int
That function would have to be called with a timer or something to query the result.
Another possibility would be to just keep the result of the last save.
(Or just leave it the way it is: saves are not going wrong very often)
There are enough async calls in the system function library now that it may be worth creating a new callback to handle them.
I’m thinking about adding
On AsyncResult(id : integer, status : integer, errorMessage : string)
...
End
This would be triggered at the end of certain asynchronous calls. So for example, there could be an id that represents a savePreset operation to which you could then respond.
The problem is being able to distinguish multiple async calls of the same kind. Suppose you try to save three presets at the same time. You would get a callback after each save but how would you know which was which? Updating the language to support this is non-trivial, particularly since there’s no current mechanism to support overloading.
If the SaveGPPreset() function would return a unique id (handle, cookie, whatever) then this id could be compared to the id passes by the callback function.
Nice approach btw, much better then polling for results
Yes, but that means that the user has to be able to create (or be aware of) that unique id and that means that the system functions would have to be changed (which would break existing code) or new system functions would have to be added for anything that behaves asynchronously.
There are other approaches that could be taken, e.g.
SavePreset(...)
when finished(status : integer, errorMessage : String) do // Optional callback
///
end
so an optional when clause could be appended to any function call (that doesn’t return something)
but I’m just not sure it’s worth the effort.
The id could be just an ever increasing number that you internally create. Using an int32 that would be 2,000,000,000 saves before you run out. That’s about 63 years saving a preset each second.
The progammer saves the id returned by SaveGPPreset(). Of course, SaveGPPreset() has to be modified, because at this moment it is returning nothing.
Then, when the callback arrives, the programmer can compare it to the id the callback passes:
Var
saveBtn : Widget
eq : PluginBlock
saveEq : int
On WidgetValueChanged(newValue : double) from saveBtn
if newValue == 1.0
then
saveEq = SaveGPPreset(eq, "filename")
end
End
On AsyncResult(id : integer, status : integer, errorMessage : string)
if id == saveEq
then
…
end
End
The programmer should keep track of the outstanding saves, maybe by blocking saving, while one is still in progress, etc. Taking that burden away in a generalized way would be a real headache.
Yeah, sorry, I guess I wasn’t clear about the issue. While you’re correct that that would work for SaveGPPreset (since it is a new function not yet released), it would not solve the general problem.
There are already many other system functions that require asychronous handling, e.g.
LoadGPPreset
SetPluginEditorXYPosition
RefreshWidgetsMappedToPlugin
Select Preset
ShowChordProWindow
MoveSong
ClosePlugin
OpenPlugin
ReplacePlugin
Notify
…
At least 50 functions need this. They would all have to be changed or extended so that you could (say) wait for a plugin to open, wait for the ChordPro window to open, etc., etc
For the moment, couldn’t we just use " FileExists" to check to see the if the GPPreset exists before we try to save it. … and then do the same thing after we save the GPpreset to make sure it was saved?
I know we are talking about using the LoadGpPreset and SaveGPPreset in scripting, but it would be nice if a user could just click on a button (SaveGPPreset) and GP would just ask for a FileName … and then do the rest?
Theoretically, the file could be halfway saving, just be the previous version, have failed during saving, etc. Luckily in most cases saving succeeds, but the existence of the file is not really conclusive or deterministic