Board index FlightGear Development Canvas

Just a little thing in the menu - ruler

Canvas is FlightGear's new fully scriptable 2D drawing system that will allow you to easily create new instruments, HUDs and even GUI dialogs and custom GUI widgets, without having to write C++ code and without having to rebuild FlightGear.

Re: Just a little thing in the menu - ruler

Postby Hooray » Mon Sep 15, 2014 11:48 pm

The BB issue could be correct - IIRC, this is a relatively recent addition, so might be n/a in 3.0 - I think we used a workaround in the MapStructure.nas / SymbolCache to get the BB updated and read from the property tree, will need to check though... and by the way, I wouldn't give certain advice if this was a dead-end, so no need to argue here at all - it's not a dead-end at all, and all the cosmetics can be changed within a few minutes, functionality matters more - you can "go shopping wallpapers" in a few weeks :mrgreen: (or just ask some of our GIMP/Inkscape guys to help with that)

BTW: The BB/font size workaround is pretty clever for someone who claims not to be a programmer - the color changing stuff I added a while ago to the wiki - your changes work, but you added them directly to the helper function generating those event handlers, while such stuff should be done in the body of the event callback, see the wiki for a more extensible example - you'll come to appreciate using this kind of setup once you want to support more events, e.g. to animate the whole thing - and it is easier this way to port this properly once things stabilize. Overall, good job for fiddling with the code, and for dealing with some of the issues involved here!
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: Just a little thing in the menu - ruler

Postby Jabberwocky » Wed Sep 17, 2014 12:33 am

Okay, the BB issue is no issue then, 3.2 is coming up anyway.
The color playing was only for a quick look how it worked. I would really hate to have red menu items, so no worries, those go anyway.

I played a bit with opening windows for submenus, but I am not sure what way to go. More of a philosophical question what the thing should do in the end than a real technical problem. The old menu was basically a bar with exactly one layer of submenus. This is also how the properties are organized:

menu
item
item
...
menu
item
...

and so on.

But is that really the goal or do we need in future a solution more like

MnuObj
MnuObj
MnuObj
MnuObj
MnuObj
MnuObj
...

as in a real tree for submenus under submenus? Actually, I don't see it, but I'm pretty sure, the moment it is not implemented, it will be needed. Kind of a Murphy's law thing. I haven't seen any discussions about the menu and how it should look yet.

J.
Jabberwocky
Retired
 
Posts: 1316
Joined: Sat Mar 22, 2014 8:36 pm
Callsign: JWOCKY
Version: 3.0.0
OS: Ubuntu 14.04

Re: Just a little thing in the menu - ruler

Postby Hooray » Wed Sep 17, 2014 12:47 am

We only need to add a single "popup" function that creates popups on demand - at that point, it won't matter how complex menus get, because you can always open another popup to show a new menu. That way, the design is not affected by how flexible your menubar file is - currently, it's pretty simple, but if we want to allow people to reuse the same code for MFDs, this has to be flexible and simple - i.e. just work in terms of "popup menus" that are populated dynamically - sub menus would then merely be dealt with by registering a mouseover event to open a new popup.

So, I'd suggest to just ignore the existing menubar for now, and focus on tooltip.nas to see how popups can be created, positioned and populated. Like I said previously, that should be roughly ~50 lines of code copied and adapted from tooltip.nas, and populating the popup would then use the same method that we're currently using - either text nodes, labels or GUI buttons (which is simple to change).

Once you think about it, your code will never know much about the menubar itself - it will merely call itself recursively to present the kind of structure that it encounters in the menubar.xml file
Thus, it's more about fiddling with the code and experimenting a bit than coming up with a super-fancy design.

In very simple terms, a menubar is just a collection of buttons that are arranged in some layout (horizontal or vertical), each button has events associated with it, such as mouseover/click etc - each event can then either affect the button/label/text or -when clicked- open a new popup and start all over again.

Overall, this should be between 50-100 lines of code that are missing now to make this fully functional - and as long as you regularly provide feedback, there really isn't much that can go wrong - feel free to post your changes on the wiki so that we can take a look and contribute there.

Either way, even if you think this is too difficult (that is, supporting sub menus), I'd just proceed for now - this is simple to add later on, unless you're planning on turning this into a huge monster with more than ~300 lines of code without sharing your code? :D
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: Just a little thing in the menu - ruler

Postby Hooray » Sun Sep 21, 2014 7:51 am

I have updated the wiki to add code snippets that demonstrate how to use the new layout engine and how to place labels/buttons using examples provided by Necolatis.
Once you have access to a more recent fgfs binary, you can easily convert the menubar snippet to use proper buttons & layouts instead of the bounding box workaround, see: http://wiki.flightgear.org/Canvas_Snippets
Image


the popup thing can still be played with in the meantime - let me know if you're getting stuck somewhere and need more snippets/examples - the way, the snippets section is now being set up and structured, it will continue to be useful regardless of any particular effort, and no matter if people actually finish their projects or not
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: Just a little thing in the menu - ruler

Postby Jabberwocky » Sun Sep 21, 2014 5:08 pm

Sorry, I was busy with other stuff. Now what I planed, but well, such is life.
And yes, I actually plan to expand this a bit for some real life funtionality. So it takes more time, but well, it's just playing around.

First step (from where I was):
Menus need to be either horizontal (like the original menubar for example) or to vertical (for a pop-up menu, like classic right-mouse menus, only we can't use right-mouse because that's for looking around, but the trigger doesn't really matter at this point).

Second step:
The idea is to open menubar.xml (or any menu-xml fed into it) for multidimensional functions. The current menubar.xml has a quite strict structure:

Code: Select all
   <menu>
      <name>file</name>

      <item>
         <name>reset</name>
         <key>Shift-Esc</key>
         <binding>
            <command>reset</command>
         </binding>
      </item>

      <item>
         <name>load-tape</name>
         <key>Shift-F1</key>
         <binding>
            <command>dialog-show</command>
            <dialog-name>flight-recorder-load</dialog-name>
         </binding>
      </item>



Which is basically 1 menu level and than always "items". The idea, I move in my head is

Code: Select all
<menu>
   <name>Menu1</name>
   <menu>
      <name>Sumbenu11</name>
   </menu>
   <item>
      <name>item12</item>
      <key>whatever hotkey</key>
      <binding>
         <command>whatever command</command>
      </binding>
   </item>
... maybe another menu, another item and so on
</menu>


The approach is, as you pointed out, to have the stuff dynamically to be configured via xmls. The crux here is, we have hundreds of old planes using plane-specific menus by setting them into the static old menubar via positions in the menu. So ... what we actually need is also to hold these planes alive. The trick, I have in mnid is something like a pseudo position, kind of a dynamic position-name-list. This is a nippedt from a classid old-style menubar-extension, from a plane-set, in this case my Lineage1000.

Code: Select all
      <menubar>
         <default>
            <menu n="3">
               <item>
                  <name>autopilot</name>
                  <label>Autopilot Settings</label>
                  <binding>
                     <command>nasal</command>
                     <script>
                      var autopilot = gui.Dialog.new("sim/gui/dialogs/autopilot/dialog", "Aircraft/VIP/Systems/Lineage1000-autopilot-dlg.xml");
                      autopilot.open();
                     </script>
                  </binding>
               </item>
            </menu>

                      <menu n="5">
                         <item n="1">
                       <label>Radio Stack</label>
                  <binding>
                                        <command>nasal</command>
                                        <script>dialogs.Radio.open()</script>
                                 </binding>
                             </item>
                      </menu>

            <menu n="100">
               <label>Lineage 1000</label>
               <enabled type="bool">true</enabled>
               <item>
                  <name>autostart</name>
                  <label>Autostart</label>
                  <binding>
                     <command>property-toggle</command>
                     <property>sim/model/start-idling</property>
                  </binding>
               </item>


What this basically dooes is overwriting menu #3 to set an own autpopilot dialog. Now, in such a new canvas-menu, there is no menu #3. But with a compatibility-list, we know 3=Autopilot and we have the name "autopilot" also in this old-school menu. So we can find it by name. As long as those things are spelled the same way, that is. A comparision ignoring capitalization appears helpful here.
And if we don't find the name, we do the same as the old menu did when it was fed with an unreasonalbe high menunumber (100 for the plane specific menu for example): We add it on the same level at the end of the list.
The problem here is not to bring up a window with the menuItems, the problem is the functionality as a hole. It is nice that we can have a menuwindow in 30-50 lines of code ... but that's not the real question. The real question is, what shall be written in those windows and in which direction and what shall be done with it (a new submenu if it was a "menu", a dialog or an action if it was an "item"). And we need to trigger that "action" or "command" without wasting too much time (fps problems on small machines) by sending them around, check them thrice, dispatch them and then get them finally to a routine written in Nasal somewhere in the same plane or worse, in the central nasal-code in FGData. So, all modern elegance aside, this thing should in the end run and run effective. That makes

Third step:
Getting things triggered:
. a command (like reset for example)
- a dialog (either a system defined oen from FGData or one in the plane project), which is basically all command show-dialog)
- a nasal routine (any nasal routine, as long as the namespace is correct).

So, I was a week out of business and my time is at an essence in the near future and there is a lot work to be done. So I reread myself in the code I typed the last time I was on it and play around. Updates step by step here.

J.
Jabberwocky
Retired
 
Posts: 1316
Joined: Sat Mar 22, 2014 8:36 pm
Callsign: JWOCKY
Version: 3.0.0
OS: Ubuntu 14.04

Re: Just a little thing in the menu - ruler

Postby Jabberwocky » Sun Sep 21, 2014 6:10 pm

First step: vertical or horizontal

Code: Select all
### horizontal example ################################################################
   var myMenubar = CanvasMenubar.new(   x:getprop("/sim/startup/xsize"),
                  y:20,
                  direction:"h",
                  filename:'gui/menubar.xml');

### vertical example ################################################################
#   var myMenubar = CanvasMenubar.new(   x:-1,
#                  y:-1,
#                  direction:"v",
#                  filename:'gui/menubar.xml');


obviously, the last test was for horizontal. I added a new parameter "direction", set it to "h" for horizontal or "v" for vertical. There is not much elegenca in it because I have no idea yet what to do if someone really sends me a "W" for example, but it's enough to get the gist.
You may notice, I set the x and y parameters in the vertical example to -1. I have moved the load before the window building:

Code: Select all
   new: func(x,y, direction, filename='gui/dialogs/menubar.xml') {
      var intx=x;
      var inty=y;

      me.load(filename);
      if (x<0) {
           if (direction=="h") {
             intx=0;
             foreach(var menu; me.menubar.menu) {
                intx += size(menu.name)*12+20;
             }
          } else {
             intx=0;
             foreach(var menu; me.menubar.menu) {
                if ((size(menu.name)*12+20)>intx) {
                   intx = size(menu.name)*12+20;
                }
             }
          }
       }
       if (y<0) {
          if (direction=="v") {
             inty=0;
             foreach(var menu; me.menubar.menu) {
                inty += 12+5;
            }
         } else {
            inty=0;
            foreach(var menu; me.menubar.menu) {
               if ((size(menu.name)*12+20)>intx) {
                  inty = 12+5;
               }
            }
         }
      }
      var m = {parents: [ CanvasMenubar, CanvasApplication.new(intx,inty) ], _filename:filename };
      m.init(direction);
      return m;
   },


That's the new for CanvasMenubar. Load comes first, then a check wether x or y are <0 and if so, I let the new dalculate the x/y dimensions for the negative argument and set the window size accordingly. Still not very elegant, but it works for the tests. For now, this makes my menu adaptable in direction and size.

J.
Jabberwocky
Retired
 
Posts: 1316
Joined: Sat Mar 22, 2014 8:36 pm
Callsign: JWOCKY
Version: 3.0.0
OS: Ubuntu 14.04

Re: Just a little thing in the menu - ruler

Postby Hooray » Sun Sep 21, 2014 6:21 pm

Replying to your previous posting (not yet the last one):
This can certainly all be done, and even done in a much simpler way than you mention - but it would probably be better to focus on just replacing the existing scheme for starters and consider extending it afterwards. Once the existing scheme is supported (which would be about 3-5 more iterations IMO), adding support for vertical menus is just a matter of using a vertical layout: 3 lines of code (1 minute).

Supporting additional items can also be done, sub-menus and checkboxes would seem most important to me currently though.
But it's really just ~5 lines of code to add support for a new feature - it works analogous to how the "menu.name" is extracted by using the hash which was created via the io.read_properties/getValues() calls, i.e. isn't even much work, simply because it will convert any valid PropertyList XML into a Nasal hash, and it is up to you to decide what to do with.

One simple way to experiment with this would be to add support for an optional "tooltip" tag that is shown on "mouseover" - which is roughly 3-5 lines of code, i.e. can be done by adapting existing code.

The RMB issue won't be a problem because there are several mouse modes supported (toggle via TAB).

Allowing greater flexibility in menubar.xml would be mainly a matter of coming up with desirable features/tags and mapping those recursively to existing code, such as showing another canvas upon clicking - which would be equivalent to a popup once you think about it. Obviously, the popup would need to be positioned properly (see tooltip.nas) and sized according to its entries (use the bounding box/layout info).

Thus, there are really just a handful of building blocks missing now that would need to be integrated.

The menubar structure you envision can be trivially supported by letting the menubar code call itself for creating sub-menus/popups recursively.

you've made a good point about aircraft specific menus, but your solution would be a lot of unnecessary work - it would be much easier to simply ALSO use io.read_properties() on the aircraft-set.xml file and then use props.nas and .getValues() to get any aircraft-specific menu entries directly out of the aircraft - the only thing where that fails would be dynamically added menus via Nasal code - but even then, it would make more sense to patch the underlying Nasal code in $FG_ROOT/Nasal to redirect such menubar building to the new menubar code - roughly 5-15 lines of code, and aircraft won't ever notice the difference that way - they'll "just work".

To try this, and see for yourself, consider this snippet of pseudo code (untested):
Code: Select all
var mySetFile = "aircraft-set.xml";
var fgroot = getprop("/sim/fg-root");
var path =  fgroot ~ mySetFile;

var myXMLFile = io.read_properties(path);
var myAircraft_menu = myXMLFile.getNode("/sim/menubar").getValues();
debug.dump(myAircraftMenu);


Like I said, I haven't tested this - but something along these lines will allow you to support hard-coded aircraft-specific menus without any other work being required.
Equally, dynamically-added menus can be supported using another 5-10 lines of code

Overall, it's cool to see that you're starting to think like a programmer - but it seems a little like you have come up with a few solutions for problems that aren't quite there - so, I wouldn't over-engineer things. As you can probably tell by now, we can provide snippets of code solving this problems pretty quickly, and also explain how they work. Thus, it might be better to make this thing functional "as is", and then explore new options afterwards. Everything you've described from a functionality standpoint can be supported using another 50-80 lines of code, based on adapting existing code, and referring to snippets in tooltip.nas
The implementation strategy you propose would make this massively complex and less-flexible for other purposes - e.g. imagine someone wanting to reuse the menubar for a MFD instrument.

Performance is not going to be a problem at all - those are just bindings and you could trigger hundreds of those per frame with seeing fps/latency being affected, getting out a binding and calling it will be just 5 lines of code, and it will typically be either Nasal or fgcommands (or a combination of both), which are both really fast.

So, I'd suggest to proceed more slowly here, using less thinking in terms of "visions" and ideas, and more thinking in terms of actual experiments/code that do /something/ - I can walk you through making this thing 100% functional by posting another 5-7 snippets of code and then demonstrate how to integrate those - which would be another 3-5 evenings of spare-time coding, i.e. less than 3 hours in total probably - you'll spend more time asking questions and applying code that we post. And you'll end up with a pretty generic snippet of code that can easily be made to support all your ideas without too much work - but the approach you suggested is too complex, too narrow and too much work for someone getting started with Nasal - and the outcome would be inferior to a more generic solution.

So it's up to you obviously how you'd like to proceed - but you'll certainly get stuck pretty soon by focusing on everything else except the most basic functionality.
The key here really is to come up with a handful of generic building blocks and integrate those properly, instead of coming up with separate code for each of your features.
One you think about it, a menubar will not need much in terms of code, it's really just:

  • reading/processing XML (done)
  • creating windows/popups (done!)
  • creating buttons/widgets (done!)
  • creating event handlers (done)


Everything else is just a matter of applying existing functionality in another context, so the code can be simply reused.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: Just a little thing in the menu - ruler

Postby Hooray » Sun Sep 21, 2014 7:24 pm

regarding the code that you've posted - that will probably work, but you're basically re-inventing some kind of layout engine here - so like I said earlier, it would be better to ignore this for now, because layouting can be trivially handled by a more recent fgfs binary - it's really just two lines of Nasal/Canvas code that determine if items are arranged vertically or horizontally - thus, it makes sense to use what's available there.

Also, window/group size can be automatically computed using so called "hints" - so, I would not spend too much time re-implementing existing functionality. The main thing that will be useful regardless of your fgfs binary will be popup handling support. Otherwise, it's layouts and button widgets that will greatly simplify the existing code - see the canvas snippets wiki article for code snippets and screen shots.

So the main feature missing to make this sufficiently complete is adding popup support - and once you think about it, you already know how to create popups: by showing a canvas windows a dialog decoration - triggered by clicking on a menu via an event listener. Positioning can be implemented according to tooltip.nas
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Re: Just a little thing in the menu - ruler

Postby Jabberwocky » Sun Sep 21, 2014 8:17 pm

Oh well ... and if you could answer the question how to get the position of the mouse click ... because submenus are already popping up here (or menus somewhere in the middle of the screen if wished that way), vertical or horizotal (as set by parameters) ... I could finally bring them also to a reasonable position and go on with an endless menu tree ... and then finally do what I am interested in and make tha thing look good and call functions from there ... so, maybe, can you put ideology, philosophy, FGData, King Solomon's acnestry and Varus lost legions aside for a moment and just tell me, where to get the x/y position of a mouse click? Because even if boundingBox would work, I am sure, it does in 3.2 when 3.2 is available in some weeks as binary, it is only a little change to take that or (for reasons of backwards compatibility) to look whether it works and use either mouse click position or boundingBox depending on the situation. But for now I am blocked because bounding Box doesn't work on 3.0 and the wiki with the event classes doesn't know, that target and currentTarget are not there in 3.0 and only cause a no such member error. So, x/y, please?

By the way, I found out how the class level attributes work ... a little bit from behind through the chest right into the eye. But then, we have to work with what we got, right?

Image

and for the fun of it: pop-ups popping up. Comes with blocking of higher level menu, half mellowed positioning, size calculation, unfortunately also with headers (I have really to kill the decos now) and always the same texts (because I was too lazy to write menus under menus under menus in a xml yet).

J.
Jabberwocky
Retired
 
Posts: 1316
Joined: Sat Mar 22, 2014 8:36 pm
Callsign: JWOCKY
Version: 3.0.0
OS: Ubuntu 14.04

Re: Just a little thing in the menu - ruler

Postby Hooray » Mon Sep 22, 2014 9:07 pm

Hi, sorry for not getting back to this earlier, I completely missed your response.
That being said, you actually surprised me here :D so good job out of you !
I don't mind helping you at all, and also don't mind answering any questions - however, you have to let me decide how to respond, simply because we're obviously interested in this being useful - and while your results are indeed very encouraging, some of your earlier design musings were incredibly complex/convoluted -unnecessarily- and when I pointed that out, I wasn't criticizing you at all, but just trying to say that you are making things more difficult than necessary.

I honestly wasn't expecting that you'd make so much progress here given your earlier postings and design plans - so kudos to you. But before I post any answers/snippets, I'd like to ask you please put up your code for review so that we can help improve it and see what you're doing there after all. Once that is the case, we can provide much better targeted advice. Please do feel free to add your code snippets and screen shots to the corresponding wiki article.

Preferably, I'll answer then by adding to the "Canvas Snippets" article. However, like I said earlier, popup placement can be seen in tooltip.nas - have you taken a look at it already ? Or are you saying that tooltip.nas is using APIs that are not available to you due to your dated binary ?

PS: Sorry, I am not sure I understand what you mean by "class-level attributes" ?

PPS: The BB thing does work using some explicit .update() call IIRC - we did use that workaround in MapStructure.nas (see the SymbolCache)

EDIT: Here are the relevant bits from tooltip.nas:
re-positioning a canvas: https://gitorious.org/fg/fgdata/source/ ... p.nas#L211
getting the x/y coordinates for an event: http://wiki.flightgear.org/Canvas_Event_Handling

because I was too lazy to write menus under menus under menus in a xml yet

I suggest you look again at your menubar.xml file - you are rendering the menubar itself to each popup, even though it should be each menu's items obviously - I prepared a function named "setupMenu" to help populate each popup.
Please don't send support requests by PM, instead post your questions on the forum so that all users can contribute and benefit
Thanks & all the best,
Hooray
Help write next month's newsletter !
pui2canvas | MapStructure | Canvas Development | Programming resources
Hooray
 
Posts: 12707
Joined: Tue Mar 25, 2008 9:40 am
Pronouns: THOU

Previous

Return to Canvas

Who is online

Users browsing this forum: No registered users and 5 guests