Adding to file menu

I would like to amend the File menu as it appears in the main window once a module has been started (ie not in the VASSAL Editor window). This is the menu with “Preferences” in it.

What I would like to do is to add a list of recently saved game files for the module in question. Do we have access to the code classes in VASSAL to do this? And if so, what are the classes?

I have a methodology for capturing the list of recently saved games but this depends on being able to capture information from the save game dialogue. Is this possible?

I am assuming that I would have to save this information externally to the module and VASSAL and then read it back in when the module is opened next.

In our module (VASL) there are lots of good reasons for saving games to different directories and so just using the load save game dialogue can require much laborious resetting of the specific directory. A list of recent saves no matter the directory would handy.

Thanks.

Seems like you could accomplish a lot of what you want by using Saved Game Folders, a feature that already exists. Right-click a module and associate a new folder with it. The only “catch” is that there is no customizing the order in which saves/logs found in the associated folder are shown to you. It’s alphanumeric (ascending) order only. Double-click any save/log and it loads right up.

Hi

Thanks for this. Unfortunately it doesn’t appear to respond to what I am working on in that it displays games saved to a single local directory (at least as I understand it) for a module. What I am trying to do is to display a list of the most recent saves (so order of display matters) that have been saved across a number of saved game folders.

In our module (VASL), many players will use different folders to store: (a) campaign game scenario saves; (b) tournament game saves; (c) games with regular players, etc, all for the same module. Having to switch the load saved game dialogue from one folder to another is a PITA for me if not anyone else. A recent saves list that showed the 10 most recent saved games regardless of which folder they were saved in, would be useful.

Adding this list to the File menu would be a useful place to display it. I suspect that this will require some custom java coding and I am looking for the VASSAL code classes that handle the File menu.

You can associate as many Saved Game Folders as you wish for a given module, you aren’t limited to 1. But the display order limitation is the dealbreaker for what you’re seeking.

The Player’s File menu is set up in setupMenubarAndActions() in VASSAL.launch.PlayerWindow, if you want to see how it’s done.

To add an MRU list to that menu, you’d need to get the MenuProxy for the File menu and add and remove action items as needed. I’m not sure you can do this from code in VASL, or at least not easily. It would be simpler to do in Vassal.

I’m not sure you can do this from code in VASL, or at least not easily. It would be simpler to do in Vassal.

Thanks for this. "Simpler to do in VASSAL . . . ". Can this be done? How and by whom?

The other part is that I would need to be able to access the same game dialogue to capture information about the saved games for the list: name, date/time of save, full path. I am thinking that the list of recent saves would be stored locally, probably in a folder under the local boards directory. That file would be opened and read into the menu at start up of the VASL module.

There is a certain amount of code required to manage the list and update it as new saves take place. I have found a number of code examples for that and should be able to create a VASL class to handle that part.

I don’t see another way to do this without interacting with VASSAL to (1) obtain saved game information and (2) display the list of recent saves on the File menu.

I had thought of displaying the list on the top level panel of the Wizard below where it shows the three game options: new, online, load saved. I got stuck trying to access methods in InitialWelcomeSteps that required a WizardController object as a param. If there is a way around that and this would prove to be an easier approach for the list display, I am happy to do it this way.

Thanks.

Doug

Assuming you can intercept and locate the data you need, saving it as a Vassal module preference would be better, no need to re-invent the wheel. You can create a ‘headless’ preference that doesn’t have an entry in any of the preference dialogs.

2 Likes

That is an excellent approach. I would not have thought of it. I will give it a try, thanks.

1 Like

Concur. Using prefs to hold the paths is exactly what prefs are for.

You don’t need access to the dialog—what you need is access to the file path after a successful load. The places where you’d have that are GameState.loadGameInForeground(File) and GameState.loadGameInBackground(File). From each of those, you’d call a function that pushes the new path to the MRU queue and pops until it no longer exceeds the size limit, and then updates the items on an “Open Recent” submenu.

This wouldn’t be all that much code, should you decide to write it and submit a PR.

Well, I am willing to give it a try. I will have to open VASSAL as a dev project. I assume that the process is similar to VASL using Github. I see there are notes about it on your website.

A question though. Wouldn’t GameState.saveGame() be a better place to add the function call? I want to add recent saves to the list at the moment of the save. A player might load a game and not save it. I do that all the time; I don’t want those games added to the recent save list. Recently viewed games would be a perfectly legitimate list to create but I am planning to start with recent saves.

However, since I am doing this within VASSAL and therefore such a list would available to all VASSAL games, I will go with your preference. If you would prefer it to be Recently Viewed games then I can and will use loadGameInForeground(File) and loadGameinBackground(File).

According to your website, I should just clone VASSAL from Master. It does not suggest creating a branch first. Am I understanding this correctly?

This is something I stumbled across in module development as a means to hold hidden properties local to individual users (i.e. leave the tab name blank). Albeit unlikely, there’s no danger of a name conflict with something used by Vassal, is there?

e.g. A Global Option checkbox preference:

No, because recent files lists customarily list files which were opened, not files which were saved. It would be at odds with how most other programs do this if we listed files which were written instead of files which were read.

Yes, clone from master, then create a branch to work on.

Hi Mark,

No, the vassal preferences are completely independent and are not reflected in Global Properties unless they are specifically coded to be.

1 Like

You have pointed me to the places in VASSAL where (1) I should add code to grab the recently viewed game info and push it to the list preference and (2) where I should have code pull information from the list preference to populate the File menu.

I see the preferences folder within vassal-app which seems to contain the tools for creating and managing preferences. I assume I would use the tools to create a VASSAL preference. But from where in VASSAL should I call these tools to create a “headless” list preference? Where are other existing VASSAL preferences created?

I have my cloned VASSAL to my dev environment and am ready to go.

Create a Configurer to hold your preference. You could use a String configurer if you take care of serializing/unserializing the list of path names, but a StringArrayConfigurer probably makes more sense. This configurer will never be displayed anywhere, but Prefs only work via Configurers, we just use it to hold and encode/decode the value

final String[] mruFiles = new String[0];
final StringArrayConfigurer mruList = new StringArrayConfigurer("MRU_LIST", "", mruFiles );

Find the local module prefs

final Prefs prefs = GameModule.getGameModule().getPrefs()

Add our configurer to the prefs, but don’t specify a Tab name. This creates the invisible ‘headless’ pref. I

prefs.addoption("", mruList);

If no preference existed before, this creates a new preference name "“MRU_LIST” with no values. If the preference already exists, then the configurer is loaded with the value.

You can now read and write the preference value:

final String[] currentValues = prefs.getValue("MRU_LIST");
final String[2] newValues = new String[] {"a", "b");
prefs.setValue("MRU_LIST", newValues);

The StringArrayConfigurer we attached to the preferences takes care of converting between the array of strings and a singled string that is stored in the prefs file. There is no StringListConfigurer sorry, you will need to covert between Lists and Arrays.

Thanks very much for this. It is very helpful and certainly gets me started on creating the Configurer. I am also working on ASLChatter in VASL which uses a number of Configurers so I am getting comfortable with them.

I can see how this would work if I created this Configurer in VASL. However, if I understood @uckelman correctly, he was suggesting that I do it within VASSAL. In which case I would need your advice as to where to put that code in the VASSAL module.

I don’t know how you’d get an “Open Recent” onto the File menu without doing this from Vassal—specifically, from setupMenubarAndActions() in VASSAL.launch.PlayerWindow.