Improving the Joystick GUI
While this article is based on considerable community feedback, there's nobody working on this currently.
Mentors: macnab, Philosopher, Hooray, Stuart (review/commit), Zakalawe (C++ hooks )
We once talked about integrating the various Nasal capabilities added by Macnab and Philosopher right into Stuart's new JS config dialog - back then, Stuart & Zakalawe actually seemed supportive of the idea. And it would indeed not require many customizations to allow bindings to become fully runtime-configurable, including Nasal bindings and a standard library of general-purpose Nasal/JS APIs. UI-wise, we could simply reuse/integrate the existing Nasal console, so that bindings can be dynamically added and edited. At the end of the day, it's all XML, Nasal and the property tree, and some fgcommands to reinit stuff - so if people still think, that'd be useful, please speak-up and share your feature requests / ideas here.
Stuart being the developer and maintainer of the latest Joystick GUI, here's his feedback:
Stuart: Adding the ability to write Nasal for a given button was something I considered, but didn't implement. Partly this was due to time constraints, but it was also because I didn't think there was a use-case for it. The joystick configuration dialog is really targeted at new users who don't have any XML or Nasal experience. IMO anyone who knows enough to write Nasal joystick bindings will have enough knowledge to edit the joystick XML files directly and use the Nasal Console.
On a different note, I'm interested to see what bindings people are using on joysticks, to check that the set of button bindings that are supported in the configuration dialog are sufficient.
At present the dialog supports trim settings, but sets the button to be repeatable. Is there are a particular reason for not using the repeatable flag, or is it purely for people who have mode-switches and might have another (non-repeatable) function assigned to the button?
I'm very happy if someone wants to expand the Joystick GUI to include advanced features such as modifier keys, and support for arbritary Nasal snippets. I also very much like the idea of re-implementing it in Canvas, as I had to make some design decisions purely on the basis of what was possible through the XML GUI code.
If someone is working on this, it would be good to add support to allow setting of the joystick deadband - this is something that I simply haven't had the time to add.
Finally, one point that I'm sure you will bear in mind: It's critical that it remains easy to use for new users. In particular, I spent some time determining the minimum set of bindings that were really required so that someone programming their joystick for the first time wouldn't be overloaded by a massive list of possible key bindings. It might be worth having an "Advanced bindings" option that enables modifier keys and the more esoteric bindings. For example, my yoke has a slider switch that I use to control the sensitivity of the view movement control. That's really useful for my yoke in particular, but probably doesn't generalize.
Finally, I'm very happy to review any code that people want to submit, though I apologize in advance if it takes me a little time.
- To me the first step would be to have the UI include at least one "Modifier" button and/or keyboard modifiers. Then the UI can have the option of switching views between modified/not modified. This will give more available actions.
- Between us we can come up with the "actions" and code. If we can get "on the fly" switching between repeatable/non-repeatable that would make a great addition/change for Version 3.
- To make this work we definitely need to get around the repeatable/non-repeatable limitation first.
- making the repeatable flag runtime configurable should be pretty straightforward for anybody familiar with the JS code and property tree listeners (SGPropertyChangeListener).
- Without on-the-fly switching between repeatable/non-repeatable switching to modified view would have to limit the available actions to repeatable/non-repeatable based on the unmodified action.
- It will need FGCommands to do it. Then the specific joystick code can set/clear it according to needs. If no FGCommand is sent it must stay the way it is for compatibility with existing joystick xml files.
- there are obviously several ways to skin this cat - no matter if it's fgcommands or listeners - I just believe listeners to be more "direct", i.e. by simply replicating the whole config file through the property tree and just waiting for events that change things, and automatically reparsing/re-initializing things - that's after all, how the AP, AI system or the canvas work, without necessarily requiring fgcommands. On the other hand, Stuart -as the author of the JS dialog- seems to prefer fgcommands over listeners (see his clouds API). So at the end of the day it all boils down to who gets around to implementing it. It doesn't really matter if it's through listeners or fgcommands (or even something else).
- Note that the upcoming FG releases (beyond 2.12+) will include a new Nasal API for registering invididual Nasal functions as fgcommands, so that you can have very compact joystick bindings by making up new, joystick-specific, fgcommands
- it's basically the same, except obviously more universal (C++ code can use it too). It also looks better (to me) as it just used the <command> tag instead of a function call with all those tags around it (<command>nasal</command><script>call_function()</script>), and it of course requires "arguments" to be in the property tree (they can be retrieved using cmdarg() or the first argument passed to the callback function). For example, I could register a "Cyborg-X-axis" fgcommand
- this is probably going to be what bindings will look like in the future, simply because we can easily maintain a generic standard Nasal library for joystick code, without individual bindings having to be aware of implementation details - so this is pretty much the "frontend", and what things will look like to end-users, or the joystick GUI, while the backend would be based on generic and unified Nasal snippets dealing with Joystick/Yokes, Pedals etc - that would allow us provide a "stable frontend API" through Nasal-based fgcommands, whereas the back-end could evolve as needed - and the front-end would be easily editable through a corresponding GUI dialog. It would then even be possible to merge the Nasal console into everything, so that backend snippets become also customizable at runtime. Basically, more flexibility, with less coding required for people who do not want to look into scripting - also, no need for cdata or XML escaping
- Being able to edit the generated code would be nice for those who are capable of tweaking it. (Such as a personal preference for slew-rate.) Dynamic re-inits would also be good.
Before creating new Canvas GUI widgets please have a look at Tom's fgdata branch: https://gitorious.org/fg/toms-fgdata?p=fg:toms-fgdata.git;a=shortlog;h=refs/heads/canvas-gui-demo. Tom is currently working on creating a standard widget and layout system (similar to eg. Qt). At the moment there only exists a button widget (but already with focus, and hover/press effects) . Specifically, see $FG_ROOT/Nasal/canvas/gui.
- The UI can be worded carefully so that less-experienced users can understand the concept of doubling-up on button actions.
- And for doing it in Canvas. And for all buttons to be implemented in a nas file, not the xml file. (Standard axes can stay in the xml file.)
- For the axes, along with deadband, power as well. (With a slider in the GUI?)
- Maybe the start page with only the basic bindings, and 3 buttons: Basic, Medium and Advanced that change the view?
- Something that occurs to me is that once the system is out there people will make requests for bindings that don't exist yet. If these are implemented, unless the people use Git, they will have to wait for a new release to see them. So maybe a system where they can download just the necessary files, which be the GUI and the new glorified version of controls.nas.
- You could provide custom bindings as self-contained PropertyList-encoded XML files with embedded Nasal sections - FlightGear already supports loading PropertyList XML files via network, which is how the multiplayer list is loaded dynamically. In other words, you could take these building blocks and load/share arbitrary stuff via network, including custom joystick bindings. For details, see: Howto:Making HTTP Requests from Nasal. The tutorial also demonstrates how to use a simple web server (in fact, a single line in python) to serve a FG GUI XML file that shows a FG GUI dialog with a custom message ("Hello World").
- the tutorial uses the official fgdata repository to dynamically download the latest XML/Nasal stuff - and we've been talking about using such a method for automatically updating the Nasal APIs of the Canvas system. Also, Zakalawe is planning to provide a feature to allow aircraft to be downloaded at runtime using WebDAV (see the wiki)
- we could simply use $FG_HOME for persistence/caching - either by using the "userarchive" attribute on all JS-related snippets, so that they become persistent between sessions (see $FG_HOME/autosave.xml) or by using a custom PropertyList-XML file that stores downloaded snippets and uses a hash to check if they were already downloaded and/or need to be updated. Thus, you would only need to be online when downloading things - later on, everything would be persistent/cached.
- also, by convention, fgdata has usually been considered (and installed) as read-only - especially on "true" multi-user systems, so this should be kept in mind - it simply makes sense to have user-specific stuff in $FG_HOME, i.e. a user-specific directory for application settings. Just look at how TerraSync solves the same problem basically - because it also cannot modify $FG_ROOT, but still needs to download and store tons of data.
- The library and GUI will have to be put in a read/write folder. It does mean making FG look for it in the correct place - non-standard.
- There are a bunch of Nasal wrappers available in io.nas for loading Nasal code from different places, and there are helpers in gui.nas to load GUI dialogs from non-standard places. Keep in mind how we have a bunch of Nasal code and custom GUI dialogs in most aircraft folders, which are also "non-standard" - so that's a no-brainer.
Please feel free to add your name to this list if you are willing and able to help.
Nasal Joystick Routines
- macnab. I already have a large collection of of what would be classified as Advanced (or even Esoteric) functions written in Nasal.
Please add any ideas or suggestions you may have which are not listed above.