Passing a value to a function by reference

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?

Var

GreenButon, D101,D102,D103,D104 : Widget
LabelNamesArray: String Array

Function HighLightWidget(WidgetName : String)

SetWidgetFillColor(WidgetName, RGBToColor(1.0,1.0,1.0,1.0)) //White    
SetWidgetOutlineColor (WidgetName, RGBToColor(0.0,0.0,0.0,1.0))
SetWidgetOutlineThickness (WidgetName, 3)

End

On WidgetValueChanged(newValue : double) from GreenButon

For i = 0; i < Size(LabelNamesArray); i = i + 1 Do
    HighLightWidget(LabelNamesArray[I])
End

end

Initialization

LabelNamesArray <-- "D101"
LabelNamesArray <-- "D102"
LabelNamesArray <-- "D103"
LabelNamesArray <-- "D104"

End


Array by Reference (Rackspace) - Semantic error in “Main”: Line 15, Col 24: Argument type mismatch

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.

  1. 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
  2. You have not declared the variable i that you are using in the for loop of OnWidgetValueChanged callback.
  3. 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 :slight_smile: )

Maybe if I declared "LabelNameArray as a widget array this might work?

var LabelNameArray: Widget Array
Initialization
LabebalNamesArray ← D101
LabebalNamesArray ← D102
LabebalNamesArray ← D103
End

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.

That was correct but it should have been allowed – this is fixed for the next release

It works for me.

What does?

As @Frank1119 noted, you cannot append widgets to an array at this time.

Oooops sorry. Frank is right, you can’t append via the ArrayName ← technique.

Is there any chance you will be offering a “SaveGPPreset Function” in the near term?

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)

1 Like

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.

2 Likes

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 issue is not creating an id - the problem is how the programmer finds out which specific id value is being used each time

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

You could consider only implementing it (for now) only for SaveGPPreset (if it’s worth it anyway, or as some kind of proof-of-concept)

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