This week we’re going to talk about using save and open file dialogs with Legato. While previous posts have used these functions in scripts, we’re going to go into a lot more detail about what you can do with these dialogs this time. This is going to be a fairly limited blog in terms of code as it is difficult to create example scripts of save and open file dialogs without doing a lot of extraneous coding. As a result, this blog will contain a number of small snippets of code that are all examples of using dialogs but not a full example script. If you would like a full script using a file dialog, check out this previous script which inserts text into an HTML edit window.
Open and save dialogs have attributes that can be modified, including its name, scope, filter list, and default location. The name is a string that appears on the top bar of the dialog. The scope allows you to define a list of places that are allowed to be used for the dialog. The filter list allows you to customize the list of filters that a user can use to hide and show certain types of files. The default location allows you to set where the dialog opens.
The first example shows the basic usage. For every example today, I’ve declared a string called s1, a string called filters, and an int called rc. I’ll include this declaration on this first example but will omit from the rest for brevity’s sake. While all my examples show a file open function, you can do the same with the save file dialog.
string s1, filters;
int rc;
s1 = BrowseOpenFile("Example #1");
rc = GetLastError();
MessageBox('I', "Example #1 Returns:\r\r%s\r\rError: %08X", s1, rc);
The example will print out a string with the file and the return code from the dialog inside a message box. Most of the time the return code will be ERROR_NONE, but if the user closes or cancels the dialog, the code returned will be ERROR_CANCEL and the string s1 will be empty. In your scripts, you’ll have to be aware of this potentially happening and reacting accordingly.
We’ll now start to add things to the function call. The syntax of the three SDK functions BrowseOpenFile, BrowseOpenFiles, and BrowseSaveFile are all the same.
String = BrowseOpenFile(string title, [string filter], [string path]);
The only major difference with these functions is that the BrowseOpenFiles function returns an array of strings. If you omit a filter it will default to “All Files (*.*)” with nothing else in the file type list. The path will default to the last path for the title string. If it is the first time that title has been used, it will default to the application’s current working directory.
Let’s try adding some file type filters. The next example uses an open file dialog, and we will filter for csv or HTML files.
filters = "All Files *.*|*.*&Comma Delimited Data *.csv|*.csv&HTML Files *.htm|*htm;*html";
s1 = BrowseOpenFile("Example #2", filters);
rc = GetLastError();
MessageBox('I', "Example #2 Returns:\r\r%s\r\rError: %08X", s1, rc);
A filter string needs to be formatted correctly or else your function will not work or can produce unexpected behavior. The proper formatting is as follows:
Text showing in filter box|filter&additional list items|filter;secondary filter&etc|filter
So for example, a filter looking for an XML or GFP file would look like this:
XML Files (*.xml)|*.xml&Project Files (*.gfp)|*.gfp&All Files (*.*)|*.*
Finally, let’s look at using all three parameters (the title, the path, and the filters) together. Let’s say we’re writing a script to work with GoFiler project files that are usually stored on the D:\ drive of a user’s computer. We want to have the script always start in the root of D:\ so that the user can find the folder they’re working in right there and then select the file. We would have something that looks like this:
filters = "Project Files (*.gfp)|*.gfp&All Files (*.*)|*.*";
s1 = BrowseOpenFile("Example #3", filters, "D:\\");
rc = GetLastError();
MessageBox('I', "Example #3 Returns:\r\r%s\r\rError: %08X", s1, rc);
Finally we’re going to talk about scope. You can add scope to your script to limit the places from which a user can open files from or to which the user can save files. By default the program can save and load files from anywhere the script has read/write access. Once you add a scope restriction, it will limit the user to only using places specified in the allowed scope.
There are two functions relating to scope: the BrowseAddOpenScope function and the BrowseAddSaveScope function. Both take a string parameter. The string you pass it will be added to the allowed scope. You can add up to 10 locations to the scope restriction table one at a time using these functions. If you pass an empty string, it will clear the scope restriction table. Scope restrictions, once added by your script, will stay in effect even after the script has ended, so generally if you are adding scope restrictions you will want to clear them later. However, this does mean a start up script can limit the directories users can open and save into in a production environment.
Our final example will be a modification of our previous one. Before we assumed that a file would be on a user’s D:\ drive. Our last example limits a user to only use the D:\ drive.
BrowseAddOpenScope("D:\\");
filters = "Project Files (*.gfp)|*.gfp&All Files (*.*)|*.*";
s1 = BrowseOpenFile("Example #4", filters, "D:\\");
rc = GetLastError();
MessageBox('I', "Example #4 Returns:\r\r%s\r\rError: %08X", s1, rc);
BrowseAddOpenScope("");
Here we force the user to open from the D:\ drive, add a filter for .gfp files and all files, set the open dialog to start in the root of the D:\ drive, and then clear the scope restrictions after we’re done.
Save and Open dialogs have a large level of customizability, which allows you as a developer to exactly control what a user sees and has access to. Using these dialogs as tools allows you to easily get files and file locations from users and allows you to spend more time on the rest of the script, rather than spending extra time gathering information. These examples are all very basic, but with some simple logic on the other end you can easily add all of the possible outcomes from a user’s input and give intelligent feedback if they give you something that you don’t want as input.
Joshua Kwiatkowski is a developer at Novaworks, primarily working on Novaworks’ cloud-based solution, GoFiler Online. He is a graduate of the Rochester Institute of Technology with a Bachelor of Science degree in Game Design and Development. He has been with the company since 2013. |
Additional Resources
Novaworks’ Legato Resources
Legato Script Developers LinkedIn Group
Primer: An Introduction to Legato