<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.flightgear.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Hcc23</id>
	<title>FlightGear wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.flightgear.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Hcc23"/>
	<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/Special:Contributions/Hcc23"/>
	<updated>2026-04-09T14:03:50Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.39.6</generator>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Talk:A_standard_CDU_framework_for_FlightGear&amp;diff=40012</id>
		<title>Talk:A standard CDU framework for FlightGear</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Talk:A_standard_CDU_framework_for_FlightGear&amp;diff=40012"/>
		<updated>2012-02-02T23:05:12Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Scratching my head about what &amp;quot;my&amp;quot; CDU actually did do... */ new section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Can we have the standard CDU framework discussion here?&lt;br /&gt;
&lt;br /&gt;
Anyway, about the layers, I was thinking - display animations (OSGText), 3D model, central functioning - MENU, FUNCTIONS/PAGES). About the menu and function/pages, we could use a common menu and have the best/most functional functions/pages from each of the CDUs combined.&lt;br /&gt;
&lt;br /&gt;
- Omega&lt;br /&gt;
&lt;br /&gt;
== Scratching my head about what &amp;quot;my&amp;quot; CDU actually did do... ==&lt;br /&gt;
&lt;br /&gt;
Well, hello (again, I should say)&lt;br /&gt;
&lt;br /&gt;
Some initial information: I am not longer &amp;quot;working&amp;quot; with FlightGear. My project has moved on and &amp;quot;we&amp;quot; don't need a FlightGear CDU anymore, hence I won't be able to spend &amp;quot;work time&amp;quot; on it...&lt;br /&gt;
&lt;br /&gt;
That aside, here are some things I think to remember from &amp;quot;my&amp;quot; CDU:&lt;br /&gt;
&lt;br /&gt;
* It isn't &amp;quot;mine&amp;quot;. I started of on Gjis CDU, took his 3D graphics and started to work my way in from his initial XML based approach so all the kudos to him as I learned from his. That said, I am going to drop the &amp;quot;&amp;quot; and call my CDU the one you can get from gitorious https://gitorious.org/~hcc23.&lt;br /&gt;
* Beware of NASAL and performance: I encourage you to checkout my CDU and run it (if it still is compatible)... The frame rate really really drops :( I remember having some IRC discussions about that and think to remember the problem being the NASAL garbage collector...&lt;br /&gt;
* I tried to generate a rather reusable piece of software. &lt;br /&gt;
** The 3D model is seprate&lt;br /&gt;
** The key binding is separate&lt;br /&gt;
** The [[Nasal_CDU_Framework| backend]] to generate (Honywell-)CDU style pages is independent from the code that defines the content of those pages&lt;br /&gt;
** There is some [[Howto:_Coding_a_Boeing_CDU#The_Code_Framework | documentation]] on how to actually generate content for the pages.&lt;br /&gt;
&lt;br /&gt;
Overall I think having a [[CDU]] would make FlightGear an even better/cooler sim. Chopping the problem up also seems to be a great idea.&lt;br /&gt;
&lt;br /&gt;
Unfortunately I won't have the same availability as when I coded the stuff that now sits in my gitorious account and most likely I won't be able to fully understand my code either. And to make matters worse, I most likely won't check this page very often (although I will keep trying to keep up at least a couple of days/weeks...) So send me a private message via the forum as that reaches me and I can then respond. (Or google any of my email addresses and ping me directly...)&lt;br /&gt;
&lt;br /&gt;
Thanks for making FlightGear the really cool sim it is :)&lt;br /&gt;
&lt;br /&gt;
[[User:Hcc23|Hcc23]] 18:05, 2 February 2012 (EST)&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Development_workflow&amp;diff=31796</id>
		<title>Development workflow</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Development_workflow&amp;diff=31796"/>
		<updated>2011-05-19T18:19:47Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
This page outlines some ''first steps'' on how to do (code) development for [[FlightGear]].&lt;br /&gt;
&lt;br /&gt;
=The Big Picture=&lt;br /&gt;
&lt;br /&gt;
The [[FlightGear]] sources are hosted at Gitorious: https://gitorious.org/fg .&lt;br /&gt;
&lt;br /&gt;
As a safety precaution, the commit access to those repositories is not public and hence development work has to be somewhat ''staged''.&lt;br /&gt;
&lt;br /&gt;
Once this staging is done, there are two major possible ways for the done work to find its way back into the official sources:&lt;br /&gt;
&lt;br /&gt;
# A person with commit access ''OK's'' the work and commits it, using her or his account.&lt;br /&gt;
# A [[GIT Merge Request|merge request]] has been filed and somebody with the proper access performs the merge.&lt;br /&gt;
&lt;br /&gt;
Fortunately the ''staging'' necessary for both approaches is essentially the same&lt;br /&gt;
&lt;br /&gt;
=Using a Personal Gitorious Repository=&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' This is essentially my tale. AndersG guided me through the process and I wanted to record/report it somewhere. [[User:Hcc23|Hcc23]] 13:59, 19 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
# Create (or login to) a Gitorious account at https://www.gitorious.org/login&lt;br /&gt;
## If you have a Google account (e.g. Gmail), you can use that to login:&lt;br /&gt;
## Click ''Or log in with OpenID''&lt;br /&gt;
## Enter &amp;lt;tt&amp;gt;https://profiles.google.com/yourGoogleLoginName&amp;lt;/tt&amp;gt;, replacing &amp;lt;tt&amp;gt;yourGoogleLoginName&amp;lt;/tt&amp;gt; with your Google login (i.e. whatever you have in front of @googlemail.com or @gmail.com).&lt;br /&gt;
&lt;br /&gt;
[[File:Gitorious_cloning_button.png|thumb|400px|The '''Clone repository''' button on https://gitorious.org/fg copies (clones) a Gitorious repository into ones private Gitorious account.]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=File:Gitorious_cloning_button.png&amp;diff=31794</id>
		<title>File:Gitorious cloning button.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=File:Gitorious_cloning_button.png&amp;diff=31794"/>
		<updated>2011-05-19T18:01:32Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: Highlighting the &amp;quot;Clone&amp;quot; button on Gitorious. This button will create a clone of a repository within one's own Gitorious account.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Highlighting the &amp;quot;Clone&amp;quot; button on Gitorious. This button will create a clone of a repository within one's own Gitorious account.&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Development_workflow&amp;diff=31793</id>
		<title>Development workflow</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Development_workflow&amp;diff=31793"/>
		<updated>2011-05-19T17:59:32Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: Started with my tale.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page outlines some ''first steps'' on how to do (code) development for [[FlightGear]].&lt;br /&gt;
&lt;br /&gt;
=The Big Picture=&lt;br /&gt;
&lt;br /&gt;
The [[FlightGear]] sources are hosted at Gitorious: https://gitorious.org/fg .&lt;br /&gt;
&lt;br /&gt;
As a safety precaution, the commit access to those repositories is not public and hence development work has to be somewhat ''staged''.&lt;br /&gt;
&lt;br /&gt;
Once this staging is done, there are two major possible ways for the done work to find its way back into the official sources:&lt;br /&gt;
&lt;br /&gt;
# A person with commit access ''OK's'' the work and commits it, using her or his account.&lt;br /&gt;
# A [[GIT Merge Request|merge request]] has been filed and somebody with the proper access performs the merge.&lt;br /&gt;
&lt;br /&gt;
Fortunately the ''staging'' necessary for both approaches is essentially the same&lt;br /&gt;
&lt;br /&gt;
=Using a Personal Gitorious Repository=&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' This is essentially my tale. AndersG guided me through the process and I wanted to record/report it somewhere. [[User:Hcc23|Hcc23]] 13:59, 19 May 2011 (EDT)&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31617</id>
		<title>Nasal Display Matrix Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31617"/>
		<updated>2011-05-12T20:40:16Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;For the development of a Nasal-based [[CDU]] a main hurdle was the replication of the ''screen'' of the [[CDU]]. This Nasal code framework was created to achieve this. Hence, a lot of usage examples can be found in the sources related to the [[CDU]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Type of Replicated Display =&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The CDU utilizes a display matrix. Shown is an early version of page where the text bounding boxes have been enabled for the purpose of better showing the matrix style layout.]]&lt;br /&gt;
&lt;br /&gt;
This framework can replicate any display that uses a fixed row-and-column type screen layout, i.e. a display that has a fixed number of rows (e.g., &amp;lt;tt&amp;gt;var ROWS = 14;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;) and a fixed number of columns (e.g., &amp;lt;tt&amp;gt;var COLS = 24;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;), where each of these &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; cells holds exactly one character, resulting in a fixed-spaced font (like most console type fonts).&lt;br /&gt;
&lt;br /&gt;
Furthermore, each cell also holds the formatting information of that cell, i.e. the information on font, color, size, etc.&lt;br /&gt;
&lt;br /&gt;
Overall, such a display can be thought of as a &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt;x2 matrix (hence the name of the framework) where the first layer (i.e. all (r,c,1) elements) holds the character information for the cell (r,c) and the the second layer (i.e. all (r,c,2) elements) holds the formatting information.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Although generic, the rest of this wiki page will heavily use examples from the [[CDU]] - but the concept of the display matrix can be used for other screen like instruments as well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Nasal Code to Generate Display Matrix Text =&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;. Including this fiel into your projects should be sufficient to allow you to use a display matrix.&lt;br /&gt;
&lt;br /&gt;
== ScreenText ==&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields of the [[CDU]]. Several elements can be concatenated in a single line by stacking them in a vector, allowing for a more complex formatting of the text. Here is a brake-down of the Nasal class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ScreenText = {&lt;br /&gt;
    # the actual styles name-to-value hash-map&lt;br /&gt;
    # skipped, see above for details&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Static/Public&amp;quot;	&lt;br /&gt;
    func 	new(t,s=32,ptp=nil),&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	sprint(),&lt;br /&gt;
    func 	print(),&lt;br /&gt;
    func 	update(),&lt;br /&gt;
    &lt;br /&gt;
    (ScreenText) blank,    &lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    scalar 	me.style,&lt;br /&gt;
    scalar 	me.text,&lt;br /&gt;
    scalar 	me.property,&lt;br /&gt;
    scalar 	me.size,&lt;br /&gt;
    func 	me.mod_property(property_value),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The &amp;lt;tt&amp;gt;ScreenText.blank&amp;lt;/tt&amp;gt; does not create a recursion as it is added after the basic hash has been established -- at least this is what I believe... [[User:Hcc23|Hcc23]] 16:23, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.new&amp;lt;/tt&amp;gt; - The Constructor === &lt;br /&gt;
The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two main elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text (which is 32, what it defaults to if no other value is given); or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background. &lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the actual (multi-char) text of the element. Some limited constructor overloading can be used in order to generate different effects.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  #&lt;br /&gt;
  # 1st method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_text_verbose = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  var test_text_shorter = ScreenText.new(&amp;quot;Hello World!&amp;quot;,34); # does the same as the above as ScreenText[&amp;quot;WHITE&amp;quot;]==34&lt;br /&gt;
This would create screen text element containing the string &amp;lt;tt&amp;gt;Hello World!&amp;lt;/tt&amp;gt; and format it to be large white font. &lt;br /&gt;
&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  #&lt;br /&gt;
  # 2nd method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_prop_verbose = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  var test_prop_shorter = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],34); # result is identical to above  &lt;br /&gt;
This last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;/tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  var test_text_ = ScreenText.new(sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;)),ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
however, the benefit of the 2nd call method is that the ScreenText internally generates a record of the property (stored in &amp;lt;tt&amp;gt;me.property&amp;lt;/tt&amp;gt;) and as such allows to tie a listener to the screen text, such updating the screen text when the property changes. An example for this can be found in the [[Nasal CDU Framework]].&lt;br /&gt;
&lt;br /&gt;
The third way of instantiating a ScreenText allows a modification of the property via a function:&lt;br /&gt;
  #&lt;br /&gt;
  # 3rd method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_modprop_anonymous = ScreenText.new([&amp;quot;This runway is %f football fields long.&amp;quot;,&amp;quot;/some/where/runway-length-yards&amp;quot;,func(prop){return 0.01*prop;}],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  &lt;br /&gt;
  var divide_by_100 = func(value) { return 0.01*value;};&lt;br /&gt;
  var test_modprop_named = ScreenText.new([&amp;quot;This runway is %f football fields long.&amp;quot;,&amp;quot;/some/where/runway-length-yards&amp;quot;,divide_by_100],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
&lt;br /&gt;
What this does is comparable to this:&lt;br /&gt;
  ScreenText.new(sprintf(&amp;quot;This runway is %f football fields long.&amp;quot;,divide_by_100(getprop(&amp;quot;/some/where/runway-length-yards&amp;quot;))),ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
Again, but with the benefit of registering the function as well as the property and output format in the respective ''private'' variables &amp;lt;tt&amp;gt;me.mod_property&amp;lt;/tt&amp;gt;,&amp;lt;tt&amp;gt;me.property&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;me.format&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Example for a changing the style:'''&lt;br /&gt;
&lt;br /&gt;
A slight cheat (but a useful one) is incorporated when it comes to altering the style of a ScreenText element. One example for that would be toggle fields in the CDU in where the text essentially stays the same, but it's color (i.e. style) changes depending on a property. The third method of a constructor call can be used to achieve this, here exemplified by one of the before mentioned CDU toggle fields:&lt;br /&gt;
  var toggle_OnOff_on = func(decision_string) {&lt;br /&gt;
    if (decision_string==&amp;quot;ON&amp;quot;) {&lt;br /&gt;
      # &amp;quot;me&amp;quot; is the screen text object that calls this function...&lt;br /&gt;
      me.style = ScreenText[&amp;quot;GREEN&amp;quot;];&lt;br /&gt;
    } else {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;white&amp;quot;];&lt;br /&gt;
    };&lt;br /&gt;
    return &amp;quot;ON&amp;quot;;&lt;br /&gt;
  };&lt;br /&gt;
  &lt;br /&gt;
  var toggle_OnOff_off = func(decision_string) {&lt;br /&gt;
    if (decision_string==&amp;quot;OFF&amp;quot;) {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;GREEN&amp;quot;];&lt;br /&gt;
    } else {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;white&amp;quot;];&lt;br /&gt;
    }; &lt;br /&gt;
   return &amp;quot;OFF&amp;quot;;&lt;br /&gt;
  };&lt;br /&gt;
  &lt;br /&gt;
  var field_efisCtl = Field.new(ScreenText.new(&amp;quot;EFIS CTL&amp;quot;,ScreenText[&amp;quot;white&amp;quot;]),[&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_off]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;lt;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_on]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
  ],toggle_efisCtl);&lt;br /&gt;
&lt;br /&gt;
The important part here is the generation of the involved ScreenTexts. Note how the first and third indented ScreenTexts make use of the third form of calling the ScreenText constructor. However, when you check the property modification functions &amp;lt;tt&amp;gt;toggle_OnOff_on&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;toggle_OnOff_off&amp;lt;/tt&amp;gt;, you will find that they always return the same string (&amp;quot;ON&amp;quot; or &amp;quot;OFF&amp;quot;,resp.) which then is rendered in the &amp;lt;tt&amp;gt;sprintf()&amp;lt;/tt&amp;gt; fashion. However, making use of the &amp;lt;tt&amp;gt;me&amp;lt;/tt&amp;gt; Nasal element, both of these functions alter the style via &amp;lt;tt&amp;gt;me.style&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.sprint()&amp;lt;/tt&amp;gt; - Generating a String ===&lt;br /&gt;
&amp;lt;tt&amp;gt;.sprint()&amp;lt;/tt&amp;gt; does exactly that: it takes the associated &amp;lt;tt&amp;gt;me&amp;lt;/tt&amp;gt; screen text, runs it through the formatting process if necessary, and returns a Nasal scalar-type string.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.print()&amp;lt;/tt&amp;gt; - Print to the Console ===&lt;br /&gt;
This function simply wraps a Nasal &amp;lt;tt&amp;gt;print(...)&amp;lt;/tt&amp;gt; around the &amp;lt;tt&amp;gt;.sprint()&amp;lt;/tt&amp;gt;, effectively printing the screen text into the console. This function might be helpful for debugging purposes.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.update()&amp;lt;/tt&amp;gt; - Reparsing the ScreenText ===&lt;br /&gt;
This function has no apparent output or return value, but the internal variables, most importantly the &amp;lt;tt&amp;gt;.size&amp;lt;/tt&amp;gt; is updated. This might be necessary when SreenText elements are tied to properties which could result in a non-constant length of the ScreenText string.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ''Writing'' the Display Matrix ==&lt;br /&gt;
There are some other functions that actually do the ''writing'' into the display matrix, which lives in the property tree. (From there the XML takes it and renders it in the 3D world. But that happens without any necessary interactions.)&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;resetDisplayMatrix&amp;lt;/tt&amp;gt; - Erasing===&lt;br /&gt;
A call to this function via &lt;br /&gt;
  resetDisplayMatrix();&lt;br /&gt;
sets all elements in the display matrix to the &amp;lt;tt&amp;gt;ScreenText.blank&amp;lt;/tt&amp;gt;, i.e. an empty string with a style of &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;dumpDisplayMatrix&amp;lt;/tt&amp;gt; - Dump Content to Console===&lt;br /&gt;
A call to &lt;br /&gt;
  dumpDisplayMatrix(note=&amp;quot;Just testing what happens...&amp;quot;);&lt;br /&gt;
prints the current display matrix to the console, also putting the optional string &amp;lt;tt&amp;gt;note&amp;lt;/tt&amp;gt; above it, which might be helpful for debugging or identifying which call to &amp;lt;tt&amp;gt;dumpDisplayMatrix()&amp;lt;/tt&amp;gt; actually produced the output.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;writeDisplayMatrixText&amp;lt;/tt&amp;gt; - Print into the Display Matrix===&lt;br /&gt;
This is the actual ''print'' command for the display matrix. The full syntax of the function is &lt;br /&gt;
  writeDisplayMatrixText(row,col=0,element=nil,mode=nil)&lt;br /&gt;
&lt;br /&gt;
'''row''' is the row of the display matrix you want to print to. Rows are zero indexed.&lt;br /&gt;
&lt;br /&gt;
'''col''' is the column you want to (start) writing at. At this point the column can mostly be set to/left at its default of 0 as the &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; takes care of a lot of things.&lt;br /&gt;
&lt;br /&gt;
'''element''' is the vector of ScreenText(s) to be written. Currently the element has to be a vector, even if only one ScreenText is inside it.&lt;br /&gt;
&lt;br /&gt;
'''mode''' can be set to &amp;quot;left&amp;quot;/&amp;quot;L&amp;quot;, &amp;quot;right&amp;quot;/&amp;quot;R&amp;quot;, or &amp;quot;center&amp;quot;/&amp;quot;C&amp;quot; to align the text respectively in the row. Hence, if a mode is set, the col input is currently unused.&lt;br /&gt;
&lt;br /&gt;
One special case of the command is when the element is a nil. In that case the row set by the row input will be completely erased!&lt;br /&gt;
&lt;br /&gt;
= Internal Representation of the Data =&lt;br /&gt;
&lt;br /&gt;
As the screen has a fixed resolution (governed by the &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; variables), internally the (0-indexed) screen is held in the FlightGear property tree. For the [[CDU]] the (0,0) cell is stored like this&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable holding the single character that should be displayed, i.e. representing the first layer of the display matrix. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal scalar-type variable (registering as a double in the property tree although it only requires integers), representing the formatting information, i.e. the second layer of the display matrix.&lt;br /&gt;
&lt;br /&gt;
The initial part of that property tree path, i.e. &amp;lt;tt&amp;gt;/instrumentation/cdu&amp;lt;/tt&amp;gt; is actually held in a variable named &amp;lt;tt&amp;gt;PROP&amp;lt;/tt&amp;gt; (which in case of the [[CDU]] is set to the before mentioned value), whereas the display matrix framework adds the &amp;lt;tt&amp;gt;./display/...&amp;lt;/tt&amp;gt; subtree.&lt;br /&gt;
This should allow for an easy inclusion of the framework into other instruments as long as that instrument is properly scoped, i.e. it provides its own (locally scoped) &amp;lt;tt&amp;gt;var PROP = &amp;quot;/where/ever&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Style Encoding ==&lt;br /&gt;
The style of the char to be displayed is encoded via a binary-style key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt; 17&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name that is aimed at capturing the features of that style,for example, &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt;. Each name is then mapped to a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
# The first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;).&lt;br /&gt;
# The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background. So &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; would be the name for a small font size, white font color, non-shaded formatting, whereas &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt; would be standing for a large font size, cyan font color, shaded background formatting.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet correctly implemented but the framework provides an internal hack to make use of some of the formatting information. [[User:Hcc23|Hcc23]] 09:50, 10 May 2011 (EDT) &lt;br /&gt;
&lt;br /&gt;
== The XML Style Interface ==&lt;br /&gt;
In order to make use of the Nasal-maintained data, the 3D model representing the screen has to access the data in the property tree and render it according to the style set there.&lt;br /&gt;
&lt;br /&gt;
This is accomplished via two pieces of code:&lt;br /&gt;
# the fairly generic &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt;&lt;br /&gt;
# a fairly specific and elaborate section in the model specific XML (in case of the [[CDU]] that would be &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== The XML Template for Display Matrix Text ===&lt;br /&gt;
The &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt; essentially provides a template for the creation of an OSGText element, just as other text that is rendered in the the 3D cockpit. The file is comprised of a few sub-sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  &amp;lt;PropertyList&amp;gt;&lt;br /&gt;
    &amp;lt;params&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/params&amp;gt;&lt;br /&gt;
    &amp;lt;text&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/text&amp;gt;&lt;br /&gt;
    &amp;lt;animation&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/animation&amp;gt;&lt;br /&gt;
  &amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; section provides a place for all the elements that need to be altered/adapted for the individual characters, i.e. whenever the template is actually used, the values in this section (and if possible this section only) should be changed. More on that later...&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;text&amp;gt;...&amp;lt;/text&amp;gt;&amp;lt;/tt&amp;gt; section provides the actual ''model'' for the OSGText. It is a fairly complete set of settings from &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;animation&amp;gt;...&amp;lt;/animation&amp;gt;&amp;lt;/tt&amp;gt; section then alters the rendering of the text, particularly it provides for a ''material'', i.e. the color. This section ''should'' hence do the translation from the different styles into the corresponding difference in the rendering. (Which, AFAIK, should be possible through different materials [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)).&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I mentioned earlier that I needed to build in a cheat. Well, it is in the animations section. For some reason I couldn't wrap my head around how to change the color of an animation based upon a variable in the Nasal scope, i.e. a condition like &amp;lt;tt&amp;gt;IF A=1 DO...&amp;lt;/tt&amp;gt;. So I made the display matrix framework put in some extra variables which I did manage to poll, using several animations which get enabled based on mutually exclusive conditions. One drawback (other than it seriously looking lousy) is that I couldn't manage to use that cheat to change the font size. I assume that this is due to the fact that the size is set outside the animation and directly in the text block... So ANY hint on how to generate the text in different sizes (using XML) would be greatly appreciated. [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== The XML ''Instantiation'' of Display Matrix Text ===&lt;br /&gt;
&lt;br /&gt;
So the real work happens to happen inside the CDU's 3D model XML, &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;. In that file, each an every (r,c) cell of the display matrix gets to be a separate model (yes, that means ton's of XML code...). Here is how one such instance looks like:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  			&amp;lt;style&amp;gt;/instrumentation/cdu/display/row-0/col-0/style&amp;lt;/style&amp;gt;&lt;br /&gt;
  			&amp;lt;font-color&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-color&amp;lt;/font-color&amp;gt;&lt;br /&gt;
  			&amp;lt;font-size-m&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-size-m&amp;lt;/font-size-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What happens here is also two-fold:&lt;br /&gt;
# First, the relevant sections in the &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; block get overwritten. &lt;br /&gt;
# Second, the model get's (re-)located at/to the correct position.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Here again traces of my cheat are visible. In theory one wouldn't need the &amp;lt;tt&amp;gt;font-color&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;font-size&amp;lt;/tt&amp;gt; variables, as this information is already encoded in the &amp;lt;tt&amp;gt;style&amp;lt;/tt&amp;gt; variable. However, I couldn't get that to work... [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
As this XML is extremely repetitive, a MATLAB script was used to ''autocode'' this section. (The script below will output a file, &amp;lt;tt&amp;gt;FILENAME&amp;lt;/tt&amp;gt;, containing all the XML which then could be copy-pasted into the model's XML.):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
          &lt;br /&gt;
          charPath  = sprintf('/instrumentation/cdu/display/row-%d/col-%d',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;style&amp;gt;%s&amp;lt;/style&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-color&amp;gt;%s&amp;lt;/font-color&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-size-m&amp;gt;%s&amp;lt;/font-size-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          [charPath '/char'],...&lt;br /&gt;
          [charPath '/style'],...&lt;br /&gt;
          [charPath '/font-color'],...&lt;br /&gt;
          [charPath '/font-size-m'],...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31616</id>
		<title>Nasal Display Matrix Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31616"/>
		<updated>2011-05-12T20:38:57Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* writeDisplayMatrixText - Print into the Display Matrix */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
For the development of a Nasal-based [[CDU]] a main hurdle was the replication of the ''screen'' of the [[CDU]]. This Nasal code framework was created to achieve this. Hence, a lot of usage examples can be found in the sources related to the [[CDU]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Type of Replicated Display =&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The CDU utilizes a display matrix. Shown is an early version of page where the text bounding boxes have been enabled for the purpose of better showing the matrix style layout.]]&lt;br /&gt;
&lt;br /&gt;
This framework can replicate any display that uses a fixed row-and-column type screen layout, i.e. a display that has a fixed number of rows (e.g., &amp;lt;tt&amp;gt;var ROWS = 14;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;) and a fixed number of columns (e.g., &amp;lt;tt&amp;gt;var COLS = 24;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;), where each of these &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; cells holds exactly one character, resulting in a fixed-spaced font (like most console type fonts).&lt;br /&gt;
&lt;br /&gt;
Furthermore, each cell also holds the formatting information of that cell, i.e. the information on font, color, size, etc.&lt;br /&gt;
&lt;br /&gt;
Overall, such a display can be thought of as a &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt;x2 matrix (hence the name of the framework) where the first layer (i.e. all (r,c,1) elements) holds the character information for the cell (r,c) and the the second layer (i.e. all (r,c,2) elements) holds the formatting information.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Although generic, the rest of this wiki page will heavily use examples from the [[CDU]] - but the concept of the display matrix can be used for other screen like instruments as well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Nasal Code to Generate Display Matrix Text =&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;. Including this fiel into your projects should be sufficient to allow you to use a display matrix.&lt;br /&gt;
&lt;br /&gt;
== ScreenText ==&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields of the [[CDU]]. Several elements can be concatenated in a single line by stacking them in a vector, allowing for a more complex formatting of the text. Here is a brake-down of the Nasal class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ScreenText = {&lt;br /&gt;
    # the actual styles name-to-value hash-map&lt;br /&gt;
    # skipped, see above for details&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Static/Public&amp;quot;	&lt;br /&gt;
    func 	new(t,s=32,ptp=nil),&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	sprint(),&lt;br /&gt;
    func 	print(),&lt;br /&gt;
    func 	update(),&lt;br /&gt;
    &lt;br /&gt;
    (ScreenText) blank,    &lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    scalar 	me.style,&lt;br /&gt;
    scalar 	me.text,&lt;br /&gt;
    scalar 	me.property,&lt;br /&gt;
    scalar 	me.size,&lt;br /&gt;
    func 	me.mod_property(property_value),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The &amp;lt;tt&amp;gt;ScreenText.blank&amp;lt;/tt&amp;gt; does not create a recursion as it is added after the basic hash has been established -- at least this is what I believe... [[User:Hcc23|Hcc23]] 16:23, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.new&amp;lt;/tt&amp;gt; - The Constructor === &lt;br /&gt;
The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two main elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text (which is 32, what it defaults to if no other value is given); or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background. &lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the actual (multi-char) text of the element. Some limited constructor overloading can be used in order to generate different effects.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  #&lt;br /&gt;
  # 1st method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_text_verbose = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  var test_text_shorter = ScreenText.new(&amp;quot;Hello World!&amp;quot;,34); # does the same as the above as ScreenText[&amp;quot;WHITE&amp;quot;]==34&lt;br /&gt;
This would create screen text element containing the string &amp;lt;tt&amp;gt;Hello World!&amp;lt;/tt&amp;gt; and format it to be large white font. &lt;br /&gt;
&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  #&lt;br /&gt;
  # 2nd method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_prop_verbose = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  var test_prop_shorter = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],34); # result is identical to above  &lt;br /&gt;
This last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;/tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  var test_text_ = ScreenText.new(sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;)),ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
however, the benefit of the 2nd call method is that the ScreenText internally generates a record of the property (stored in &amp;lt;tt&amp;gt;me.property&amp;lt;/tt&amp;gt;) and as such allows to tie a listener to the screen text, such updating the screen text when the property changes. An example for this can be found in the [[Nasal CDU Framework]].&lt;br /&gt;
&lt;br /&gt;
The third way of instantiating a ScreenText allows a modification of the property via a function:&lt;br /&gt;
  #&lt;br /&gt;
  # 3rd method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_modprop_anonymous = ScreenText.new([&amp;quot;This runway is %f football fields long.&amp;quot;,&amp;quot;/some/where/runway-length-yards&amp;quot;,func(prop){return 0.01*prop;}],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  &lt;br /&gt;
  var divide_by_100 = func(value) { return 0.01*value;};&lt;br /&gt;
  var test_modprop_named = ScreenText.new([&amp;quot;This runway is %f football fields long.&amp;quot;,&amp;quot;/some/where/runway-length-yards&amp;quot;,divide_by_100],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
&lt;br /&gt;
What this does is comparable to this:&lt;br /&gt;
  ScreenText.new(sprintf(&amp;quot;This runway is %f football fields long.&amp;quot;,divide_by_100(getprop(&amp;quot;/some/where/runway-length-yards&amp;quot;))),ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
Again, but with the benefit of registering the function as well as the property and output format in the respective ''private'' variables &amp;lt;tt&amp;gt;me.mod_property&amp;lt;/tt&amp;gt;,&amp;lt;tt&amp;gt;me.property&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;me.format&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Example for a changing the style:'''&lt;br /&gt;
&lt;br /&gt;
A slight cheat (but a useful one) is incorporated when it comes to altering the style of a ScreenText element. One example for that would be toggle fields in the CDU in where the text essentially stays the same, but it's color (i.e. style) changes depending on a property. The third method of a constructor call can be used to achieve this, here exemplified by one of the before mentioned CDU toggle fields:&lt;br /&gt;
  var toggle_OnOff_on = func(decision_string) {&lt;br /&gt;
    if (decision_string==&amp;quot;ON&amp;quot;) {&lt;br /&gt;
      # &amp;quot;me&amp;quot; is the screen text object that calls this function...&lt;br /&gt;
      me.style = ScreenText[&amp;quot;GREEN&amp;quot;];&lt;br /&gt;
    } else {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;white&amp;quot;];&lt;br /&gt;
    };&lt;br /&gt;
    return &amp;quot;ON&amp;quot;;&lt;br /&gt;
  };&lt;br /&gt;
  &lt;br /&gt;
  var toggle_OnOff_off = func(decision_string) {&lt;br /&gt;
    if (decision_string==&amp;quot;OFF&amp;quot;) {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;GREEN&amp;quot;];&lt;br /&gt;
    } else {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;white&amp;quot;];&lt;br /&gt;
    }; &lt;br /&gt;
   return &amp;quot;OFF&amp;quot;;&lt;br /&gt;
  };&lt;br /&gt;
  &lt;br /&gt;
  var field_efisCtl = Field.new(ScreenText.new(&amp;quot;EFIS CTL&amp;quot;,ScreenText[&amp;quot;white&amp;quot;]),[&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_off]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;lt;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_on]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
  ],toggle_efisCtl);&lt;br /&gt;
&lt;br /&gt;
The important part here is the generation of the involved ScreenTexts. Note how the first and third indented ScreenTexts make use of the third form of calling the ScreenText constructor. However, when you check the property modification functions &amp;lt;tt&amp;gt;toggle_OnOff_on&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;toggle_OnOff_off&amp;lt;/tt&amp;gt;, you will find that they always return the same string (&amp;quot;ON&amp;quot; or &amp;quot;OFF&amp;quot;,resp.) which then is rendered in the &amp;lt;tt&amp;gt;sprintf()&amp;lt;/tt&amp;gt; fashion. However, making use of the &amp;lt;tt&amp;gt;me&amp;lt;/tt&amp;gt; Nasal element, both of these functions alter the style via &amp;lt;tt&amp;gt;me.style&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.sprint()&amp;lt;/tt&amp;gt; - Generating a String ===&lt;br /&gt;
&amp;lt;tt&amp;gt;.sprint()&amp;lt;/tt&amp;gt; does exactly that: it takes the associated &amp;lt;tt&amp;gt;me&amp;lt;/tt&amp;gt; screen text, runs it through the formatting process if necessary, and returns a Nasal scalar-type string.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.print()&amp;lt;/tt&amp;gt; - Print to the Console ===&lt;br /&gt;
This function simply wraps a Nasal &amp;lt;tt&amp;gt;print(...)&amp;lt;/tt&amp;gt; around the &amp;lt;tt&amp;gt;.sprint()&amp;lt;/tt&amp;gt;, effectively printing the screen text into the console. This function might be helpful for debugging purposes.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.update()&amp;lt;/tt&amp;gt; - Reparsing the ScreenText ===&lt;br /&gt;
This function has no apparent output or return value, but the internal variables, most importantly the &amp;lt;tt&amp;gt;.size&amp;lt;/tt&amp;gt; is updated. This might be necessary when SreenText elements are tied to properties which could result in a non-constant length of the ScreenText string.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ''Writing'' the Display Matrix ==&lt;br /&gt;
There are some other functions that actually do the ''writing'' into the display matrix, which lives in the property tree. (From there the XML takes it and renders it in the 3D world. But that happens without any necessary interactions.)&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;resetDisplayMatrix&amp;lt;/tt&amp;gt; - Erasing===&lt;br /&gt;
A call to this function via &lt;br /&gt;
  resetDisplayMatrix();&lt;br /&gt;
sets all elements in the display matrix to the &amp;lt;tt&amp;gt;ScreenText.blank&amp;lt;/tt&amp;gt;, i.e. an empty string with a style of &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;dumpDisplayMatrix&amp;lt;/tt&amp;gt; - Dump Content to Console===&lt;br /&gt;
A call to &lt;br /&gt;
  dumpDisplayMatrix(note=&amp;quot;Just testing what happens...&amp;quot;);&lt;br /&gt;
prints the current display matrix to the console, also putting the optional string &amp;lt;tt&amp;gt;note&amp;lt;/tt&amp;gt; above it, which might be helpful for debugging or identifying which call to &amp;lt;tt&amp;gt;dumpDisplayMatrix()&amp;lt;/tt&amp;gt; actually produced the output.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;writeDisplayMatrixText&amp;lt;/tt&amp;gt; - Print into the Display Matrix===&lt;br /&gt;
This is the actual ''print'' command for the display matrix. The full syntax of the function is &lt;br /&gt;
  writeDisplayMatrixText(row,col=0,element=nil,mode=nil)&lt;br /&gt;
&lt;br /&gt;
'''row''' is the row of the display matrix you want to print to. Rows are zero indexed.&lt;br /&gt;
&lt;br /&gt;
'''col''' is the column you want to (start) writing at. At this point the column can mostly be set to/left at its default of 0 as the &amp;lt;tt&amp;gt;mode&amp;lt;/tt&amp;gt; takes care of a lot of things.&lt;br /&gt;
&lt;br /&gt;
'''element''' is the vector of ScreenText(s) to be written. Currently the element has to be a vector, even if only one ScreenText is inside it.&lt;br /&gt;
&lt;br /&gt;
'''mode''' can be set to &amp;quot;left&amp;quot;/&amp;quot;L&amp;quot;, &amp;quot;right&amp;quot;/&amp;quot;R&amp;quot;, or &amp;quot;center&amp;quot;/&amp;quot;C&amp;quot; to align the text respectively in the row. Hence, if a mode is set, the col input is currently unused.&lt;br /&gt;
&lt;br /&gt;
One special case of the command is when the element is a nil. In that case the row set by the row input will be completely erased!&lt;br /&gt;
&lt;br /&gt;
= Internal Representation of the Data =&lt;br /&gt;
&lt;br /&gt;
As the screen has a fixed resolution (governed by the &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; variables), internally the (0-indexed) screen is held in the FlightGear property tree. For the [[CDU]] the (0,0) cell is stored like this&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable holding the single character that should be displayed, i.e. representing the first layer of the display matrix. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal scalar-type variable (registering as a double in the property tree although it only requires integers), representing the formatting information, i.e. the second layer of the display matrix.&lt;br /&gt;
&lt;br /&gt;
The initial part of that property tree path, i.e. &amp;lt;tt&amp;gt;/instrumentation/cdu&amp;lt;/tt&amp;gt; is actually held in a variable named &amp;lt;tt&amp;gt;PROP&amp;lt;/tt&amp;gt; (which in case of the [[CDU]] is set to the before mentioned value), whereas the display matrix framework adds the &amp;lt;tt&amp;gt;./display/...&amp;lt;/tt&amp;gt; subtree.&lt;br /&gt;
This should allow for an easy inclusion of the framework into other instruments as long as that instrument is properly scoped, i.e. it provides its own (locally scoped) &amp;lt;tt&amp;gt;var PROP = &amp;quot;/where/ever&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Style Encoding ==&lt;br /&gt;
The style of the char to be displayed is encoded via a binary-style key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt; 17&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name that is aimed at capturing the features of that style,for example, &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt;. Each name is then mapped to a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
# The first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;).&lt;br /&gt;
# The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background. So &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; would be the name for a small font size, white font color, non-shaded formatting, whereas &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt; would be standing for a large font size, cyan font color, shaded background formatting.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet correctly implemented but the framework provides an internal hack to make use of some of the formatting information. [[User:Hcc23|Hcc23]] 09:50, 10 May 2011 (EDT) &lt;br /&gt;
&lt;br /&gt;
== The XML Style Interface ==&lt;br /&gt;
In order to make use of the Nasal-maintained data, the 3D model representing the screen has to access the data in the property tree and render it according to the style set there.&lt;br /&gt;
&lt;br /&gt;
This is accomplished via two pieces of code:&lt;br /&gt;
# the fairly generic &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt;&lt;br /&gt;
# a fairly specific and elaborate section in the model specific XML (in case of the [[CDU]] that would be &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== The XML Template for Display Matrix Text ===&lt;br /&gt;
The &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt; essentially provides a template for the creation of an OSGText element, just as other text that is rendered in the the 3D cockpit. The file is comprised of a few sub-sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  &amp;lt;PropertyList&amp;gt;&lt;br /&gt;
    &amp;lt;params&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/params&amp;gt;&lt;br /&gt;
    &amp;lt;text&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/text&amp;gt;&lt;br /&gt;
    &amp;lt;animation&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/animation&amp;gt;&lt;br /&gt;
  &amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; section provides a place for all the elements that need to be altered/adapted for the individual characters, i.e. whenever the template is actually used, the values in this section (and if possible this section only) should be changed. More on that later...&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;text&amp;gt;...&amp;lt;/text&amp;gt;&amp;lt;/tt&amp;gt; section provides the actual ''model'' for the OSGText. It is a fairly complete set of settings from &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;animation&amp;gt;...&amp;lt;/animation&amp;gt;&amp;lt;/tt&amp;gt; section then alters the rendering of the text, particularly it provides for a ''material'', i.e. the color. This section ''should'' hence do the translation from the different styles into the corresponding difference in the rendering. (Which, AFAIK, should be possible through different materials [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)).&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I mentioned earlier that I needed to build in a cheat. Well, it is in the animations section. For some reason I couldn't wrap my head around how to change the color of an animation based upon a variable in the Nasal scope, i.e. a condition like &amp;lt;tt&amp;gt;IF A=1 DO...&amp;lt;/tt&amp;gt;. So I made the display matrix framework put in some extra variables which I did manage to poll, using several animations which get enabled based on mutually exclusive conditions. One drawback (other than it seriously looking lousy) is that I couldn't manage to use that cheat to change the font size. I assume that this is due to the fact that the size is set outside the animation and directly in the text block... So ANY hint on how to generate the text in different sizes (using XML) would be greatly appreciated. [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== The XML ''Instantiation'' of Display Matrix Text ===&lt;br /&gt;
&lt;br /&gt;
So the real work happens to happen inside the CDU's 3D model XML, &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;. In that file, each an every (r,c) cell of the display matrix gets to be a separate model (yes, that means ton's of XML code...). Here is how one such instance looks like:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  			&amp;lt;style&amp;gt;/instrumentation/cdu/display/row-0/col-0/style&amp;lt;/style&amp;gt;&lt;br /&gt;
  			&amp;lt;font-color&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-color&amp;lt;/font-color&amp;gt;&lt;br /&gt;
  			&amp;lt;font-size-m&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-size-m&amp;lt;/font-size-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What happens here is also two-fold:&lt;br /&gt;
# First, the relevant sections in the &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; block get overwritten. &lt;br /&gt;
# Second, the model get's (re-)located at/to the correct position.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Here again traces of my cheat are visible. In theory one wouldn't need the &amp;lt;tt&amp;gt;font-color&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;font-size&amp;lt;/tt&amp;gt; variables, as this information is already encoded in the &amp;lt;tt&amp;gt;style&amp;lt;/tt&amp;gt; variable. However, I couldn't get that to work... [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
As this XML is extremely repetitive, a MATLAB script was used to ''autocode'' this section. (The script below will output a file, &amp;lt;tt&amp;gt;FILENAME&amp;lt;/tt&amp;gt;, containing all the XML which then could be copy-pasted into the model's XML.):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
          &lt;br /&gt;
          charPath  = sprintf('/instrumentation/cdu/display/row-%d/col-%d',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;style&amp;gt;%s&amp;lt;/style&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-color&amp;gt;%s&amp;lt;/font-color&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-size-m&amp;gt;%s&amp;lt;/font-size-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          [charPath '/char'],...&lt;br /&gt;
          [charPath '/style'],...&lt;br /&gt;
          [charPath '/font-color'],...&lt;br /&gt;
          [charPath '/font-size-m'],...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31593</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31593"/>
		<updated>2011-05-11T14:26:29Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* ScratchPad */  added detail on the scratchpad&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
These are the core classes in the CDU framework. The documentation should show a brief comment on what each variable or function is intended to do, particularly the ones that are important for the '''creation''' of an actual, content-filled CDU page.&lt;br /&gt;
&lt;br /&gt;
Although Nasal as such has no support for this, the internal stuff in a class is sectioned in three categories, borrowing language from &amp;lt;tt&amp;gt;C++&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Static:''' Stuff in this section is mainly identified by being made directly as part of the &amp;lt;tt&amp;gt;hash&amp;lt;/tt&amp;gt; (as opposed to being ''tagged on'' by the the &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; constructor. Elements in here also follow a ''camelCase'' type of notation, whereas ''members'' use an ''underscore_naming_convetion''. Please note that although meant to be comparable to statics, in hindsight a lot of them would be better placed in the member section Public...&lt;br /&gt;
&lt;br /&gt;
* '''Public:''' Elements in here are created from inside the &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; constructor and follow an ''underscore_naming_convetion''. In a perfect world these would only be accessing functions, as exposing variables is always prone for trouble when the time for a redesign comes... Elements in here should be the only ones used in the creation of a page - in a perfect world.&lt;br /&gt;
&lt;br /&gt;
* '''Private:''' Elements in here are created from inside the &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; constructor and follow an ''underscore_naming_convetion''. Although readable by everybody, access to these elements should be limited to functions in the static and public parts of the classes code. Particularly no page creation (user) code should need to access this information.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' I know that I violate these rules. Yes. But I have rewritten the framework to often to (at this point) care much about it - particularly as it seems to be working. Please, feel free to correct the Nasal code I have written (which might involve the pain of revisiting the page creation sections... Sorry for that.) [[User:Hcc23|Hcc23]] 14:45, 9 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	formatOutput(input_data),&lt;br /&gt;
    func 	getScreenTextVector(),&lt;br /&gt;
    func 	new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.used_properties,&lt;br /&gt;
    vector 	me.line_data,&lt;br /&gt;
    scalar 	me.line_string_length,&lt;br /&gt;
    func 	me.enable(),&lt;br /&gt;
    func 	me.disable(),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
A field holds two lines, the label and the data line, as well as information about what the associated line select key does.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Field = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	new(label,data,key_action=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
  &lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.used_properties(),&lt;br /&gt;
    func 	me.lsk_binding(),&lt;br /&gt;
    func 	me.enable_lsk(),&lt;br /&gt;
    func 	me.disable_lsk(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    (Line)	me.label_line,	&lt;br /&gt;
    (Line) 	me.data_line,&lt;br /&gt;
    scalar 	me.lsk_active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
A SubPage is actually the main element in the CDU framework. It holds the content via its fields and manages the updating of the CDU screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var SubPage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    (Field) 	blankField,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	updateField(field, side, lsk_index),	&lt;br /&gt;
    func 	displayFields(field_vector, side),&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	new(parent_base_page,name=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar      me.separator,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    func 	me.register_field(field_pos,field),&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.parent,&lt;br /&gt;
    scalar      me.title,&lt;br /&gt;
    scalar      me.status,&lt;br /&gt;
    vector 	me.left_field,&lt;br /&gt;
    vector      me.right_field,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
A BasePage is exactly that: a base to hold sub pages. A base page most closely represents the concept of a '''page''' in a CDU.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var BasePage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	regiserInPropTree(path)&lt;br /&gt;
    func 	new(name,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.active_sub_page_id,&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    vector 	me.sub_pages,&lt;br /&gt;
    scalar 	me.title,&lt;br /&gt;
    scalar 	me.status,&lt;br /&gt;
    &lt;br /&gt;
  };  &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
The CDU is the main class for the instrument. Each simulated CDU should have one and only one CDU instance associated to it. This is intended to support multiple CDUs showing different content in the future.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var CDU = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    func 	M_ERROR(message_string),&lt;br /&gt;
    func 	M_WARNING(message_string),&lt;br /&gt;
    func 	M_NOTE(message_string),&lt;br /&gt;
    func 	M_HINT(message_string),&lt;br /&gt;
  &lt;br /&gt;
    func 	updateDisplay(),&lt;br /&gt;
    scalar 	activeBasePageID,&lt;br /&gt;
  &lt;br /&gt;
    (ScratchPad) 		scratchPad,&lt;br /&gt;
    (Timer) 			timer,&lt;br /&gt;
    (ListenerCollection) 	listOfListeners,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Additional Infrastructure =&lt;br /&gt;
The previous section was more concerned with the conceptually necessary pieces for a/the core CDU. This section introduces the other elements the framework introduces in order to code a functional CDU.&lt;br /&gt;
&lt;br /&gt;
Besides from the additional pieces presented here, there also is a page on the [[Nasal Display Matrix Framework]] which, although developed for the CDU, might be useful for any kind of fixed row-column based text-type screen in a cockpit. (As this code is conceptually separate from the CDU, its documentation is in a separate wiki page.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ScratchPad ==&lt;br /&gt;
&lt;br /&gt;
The ScratchPad is the input/output line in the CDU(s). The scratch pas as such is kind of different from the rest of the CDU(s) as the scratch pad messages are truly static, i.e. they happen to be displayed on all CDUs in the cockpit, no matter what the individual CDU is otherwise showing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ScratchPad = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	messages,&lt;br /&gt;
    scalar 	deleteString, # &amp;quot;DELETE&amp;quot;~&amp;quot;&amp;quot;&lt;br /&gt;
    func 	displayScratchPad(),&lt;br /&gt;
    func 	new(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.input_string,&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.pm_trigger,&lt;br /&gt;
    func 	me.plusminus(),&lt;br /&gt;
    func 	me.clear(pressedTime),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''messages'''&lt;br /&gt;
This vector of strings is currently not used, but it can/should hold the messages the CDU (or other systems) want to display via the scrath pad of the CDU. The messages are printed in in FIFO fashion on the scratch pad, pressing the CLR key erases the currently displayed message (and should trigger the display of the next message if one is still in the vector).&lt;br /&gt;
This functionality has not yet been tested and is just partially integrated.&lt;br /&gt;
&lt;br /&gt;
'''deleteString'''&lt;br /&gt;
This string, defaulting to &amp;lt;tt&amp;gt;DELETE&amp;lt;/tt&amp;gt; is entered into the scratch pad when it is empty and the DEL key is pressed. Having this in the scratch This behavior has not yet been tested and is just partially integrated.&lt;br /&gt;
This functionality has been tested and is working in fields that implemented the logic.&lt;br /&gt;
&lt;br /&gt;
'''displayScratchPad()'''&lt;br /&gt;
This function goes along the CDU.updateDisplay() function, however, it does not refresh the whole display but just the scratch pad line. Whenever the ScratchPad.inputString is altered and the current state should be displayed before another update to the display is called, calling this function will do that.&lt;br /&gt;
&lt;br /&gt;
'''new(...)'''&lt;br /&gt;
The constructor of the scratch pad. Should theoretically not be necessary to use this outside the framework, particularly a use whilst creating pages (i.e. content) should not be necessary.&lt;br /&gt;
&lt;br /&gt;
'''inputString'''&lt;br /&gt;
The string holding the current content of the scratch pad.&lt;br /&gt;
&lt;br /&gt;
'''plusminus()''' and '''pm_trigger'''&lt;br /&gt;
A function beeing used when the &amp;quot;+/-&amp;quot; key is pressed. The function keeps track of the current state via &amp;lt;tt&amp;gt;pm_trigger&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''clear()'''&lt;br /&gt;
This function is bound to the CLR key and erases the last character on the scratchpad (if CLR is presesd less than 1 s) or the whole scratch pad (if CLR is pressed longer than 1 s).&lt;br /&gt;
&lt;br /&gt;
== ListenerCollection ==&lt;br /&gt;
In order to update fields that are tied to a (potentially changing) property, fields that need a (potentially changing) property to compute their data can (and automatically will) register a property listener on the relevant properties whenever the relevant field is displayed. In order to unregister the listener for pages that are no longer displayed, the class CDU keeps a collection of the currently active listeners, such allowing the unregisterling for unneeded listeners.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ListenerCollection = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	add(prop, field_id, subpage_id, side, lsk_index),&lt;br /&gt;
    func 	clearAll(),&lt;br /&gt;
    func 	new(ptp=nil),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.listener_list,&lt;br /&gt;
    vector 	me.property_list,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==keyPressEvent==&lt;br /&gt;
In order to allow for a change in key effects, the CDU's 3D model's XML binds all key presses (and releases where appropriate) to a Nasal call to this function, giving the objects name (i.e. the keys name) as an argument. This name is then checked against the keys present in the KeyBinding hash (see below) and, if a match is found, that function is called.&lt;br /&gt;
&lt;br /&gt;
This function also keeps track of the current status of the plusminus, as this key either introduces a new char into the ScratchPad or toggles the last one entered.&lt;br /&gt;
&lt;br /&gt;
==KeyBinding==&lt;br /&gt;
This hash represents the current key binding. The CDU's Nasal code then overwrites these functions, effectively changing the effect of a key press. Note that the KeyBinding does not use the Button class's timing systems, but directly uses the a CDU.timer instance of the Timer class.&lt;br /&gt;
&lt;br /&gt;
= Helping Functions and Classes =&lt;br /&gt;
&lt;br /&gt;
Although written for the CDU framework, these functions are fairly general and might be useful for other code projects. Please feel free to reuse them.&lt;br /&gt;
&lt;br /&gt;
== prepend ==&lt;br /&gt;
  var prepend = func(vec, elements...) &lt;br /&gt;
This function is the counterpart to the Nasal provided append. Instead of adding stuff to the end of the vector &amp;lt;tt&amp;gt;vec&amp;lt;/tt&amp;gt; is adds them at the front, '''altering the original vector'''. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== stack ==&lt;br /&gt;
  var stack = func(elements...)&lt;br /&gt;
Instead of appending or prepending, this function simply stacks its argument vectors and '''returns a new vector''', leaving the original function arguments unaltered. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== latitude_to_string ==&lt;br /&gt;
  var latitude_to_string = func(lat_deg)&lt;br /&gt;
Take a Nasal scalar as input variable and return something like N23°14.8 . Actually, as the &amp;quot;°&amp;quot; seems to have some trouble in Helvetica, is returns something like N23*14.8. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== longitude_to_string ==&lt;br /&gt;
  var longitude_to_string = func(lon_deg)&lt;br /&gt;
Take a Nasal scalar as input variable and return something like E123°14.8 . Actually, as the &amp;quot;°&amp;quot; seems to have some trouble in Helvetica, is returns something like E123*14.8. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== Timer ==&lt;br /&gt;
A timer can be made as an instance of this class. Each timer provides the functions tic and toc, the later returning the delta time passed.&lt;br /&gt;
  var timer1 = Timer.new(); # uses /sim/time/elapsed-sec as a time source&lt;br /&gt;
  var timer2 = Timer.new(non_default_time_source_variable); # provide an alternate source of time&lt;br /&gt;
  &lt;br /&gt;
  timer1.tic(); # start the internal timer on the default time source&lt;br /&gt;
  &lt;br /&gt;
  var passed_time = timer1.toc(); # stop and reset the timer, get back the passed time in seconds.&lt;br /&gt;
This class is implemented in &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Button ==&lt;br /&gt;
As an example for the use of the before mentioned timer, this is a generic button class to be used for all kinds of GUI interfaces. Although not used in the CDU, it still might be useful for other projects that require buttons to do several different things - depending on how long it has been pushed.&lt;br /&gt;
&lt;br /&gt;
  var b_clr = Button.new(&amp;quot;CLEAR&amp;quot;); # make a new button and give it a name, stored in Button.name&lt;br /&gt;
  &lt;br /&gt;
  b_clr.addButtonAction(func() {print(&amp;quot;NO delay&amp;quot;);} ); # zero delay is the default. This function will be executed if no other criteria are met&lt;br /&gt;
  b_clr.addButtonAction(func() {print(&amp;quot;2s delay&amp;quot;);},2 ); # this function will be executed if the button has been pressed longer than 2 seconds when released.&lt;br /&gt;
  b_clr.addButtonAction(func() {print(&amp;quot;1s delay&amp;quot;);},1 ); # this function will be executed if the button has been pressed longer than 1 seconds when released.&lt;br /&gt;
&lt;br /&gt;
The corresponding XML code for your model.xml could look like this:&lt;br /&gt;
  &amp;lt;animation&amp;gt;&lt;br /&gt;
  	&amp;lt;type&amp;gt;pick&amp;lt;/type&amp;gt;&lt;br /&gt;
        &amp;lt;!-- UPDATE the name of the button object to match you case --&amp;gt;&lt;br /&gt;
  	&amp;lt;object-name&amp;gt;Btn.clr&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  	&amp;lt;action&amp;gt;&lt;br /&gt;
  		&amp;lt;button&amp;gt;0&amp;lt;/button&amp;gt;&lt;br /&gt;
  		&amp;lt;repeatable&amp;gt;false&amp;lt;/repeatable&amp;gt;  &lt;br /&gt;
  		&amp;lt;binding&amp;gt;&lt;br /&gt;
  			&amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
 			&amp;lt;nowiki&amp;gt;&amp;lt;!-- UPDATE the namespace --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  			&amp;lt;script&amp;gt;&amp;lt;![CDATA[NAMESPACE.b_clr.pressed();]]&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  		&amp;lt;/binding&amp;gt;&lt;br /&gt;
  		&amp;lt;mod-up&amp;gt;&lt;br /&gt;
  			&amp;lt;binding&amp;gt;&lt;br /&gt;
  				&amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
  				&amp;lt;nowiki&amp;gt;&amp;lt;!-- UPDATE the namespace --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  				&amp;lt;script&amp;gt;&amp;lt;![CDATA[NAMESPACE.b_clr.released();]]&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  			&amp;lt;/binding&amp;gt;&lt;br /&gt;
  		&amp;lt;/mod-up&amp;gt;&lt;br /&gt;
  	&amp;lt;/action&amp;gt;&lt;br /&gt;
  &amp;lt;/animation&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The sequence in which functions are added does not matter, note how the example created the 2 s before the 1 s functions. As a result of this, the button has to be released to work, i.e. currently it is not possible to make the button do something if the button has been pressed longer than X s and still is pressed.&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31587</id>
		<title>Nasal Display Matrix Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31587"/>
		<updated>2011-05-10T20:53:08Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* .new - The Constructor */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
For the development of a Nasal-based [[CDU]] a main hurdle was the replication of the ''screen'' of the [[CDU]]. This Nasal code framework was created to achieve this. Hence, a lot of usage examples can be found in the sources related to the [[CDU]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Type of Replicated Display =&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The CDU utilizes a display matrix. Shown is an early version of page where the text bounding boxes have been enabled for the purpose of better showing the matrix style layout.]]&lt;br /&gt;
&lt;br /&gt;
This framework can replicate any display that uses a fixed row-and-column type screen layout, i.e. a display that has a fixed number of rows (e.g., &amp;lt;tt&amp;gt;var ROWS = 14;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;) and a fixed number of columns (e.g., &amp;lt;tt&amp;gt;var COLS = 24;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;), where each of these &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; cells holds exactly one character, resulting in a fixed-spaced font (like most console type fonts).&lt;br /&gt;
&lt;br /&gt;
Furthermore, each cell also holds the formatting information of that cell, i.e. the information on font, color, size, etc.&lt;br /&gt;
&lt;br /&gt;
Overall, such a display can be thought of as a &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt;x2 matrix (hence the name of the framework) where the first layer (i.e. all (r,c,1) elements) holds the character information for the cell (r,c) and the the second layer (i.e. all (r,c,2) elements) holds the formatting information.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Although generic, the rest of this wiki page will heavily use examples from the [[CDU]] - but the concept of the display matrix can be used for other screen like instruments as well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Nasal Code to Generate Display Matrix Text =&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;. Including this fiel into your projects should be sufficient to allow you to use a display matrix.&lt;br /&gt;
&lt;br /&gt;
== ScreenText ==&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields of the [[CDU]]. Several elements can be concatenated in a single line by stacking them in a vector, allowing for a more complex formatting of the text. Here is a brake-down of the Nasal class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ScreenText = {&lt;br /&gt;
    # the actual styles name-to-value hash-map&lt;br /&gt;
    # skipped, see above for details&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Static/Public&amp;quot;	&lt;br /&gt;
    func 	new(t,s=32,ptp=nil),&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	sprint(),&lt;br /&gt;
    func 	print(),&lt;br /&gt;
    func 	update(),&lt;br /&gt;
    &lt;br /&gt;
    (ScreenText) blank,    &lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    scalar 	me.style,&lt;br /&gt;
    scalar 	me.text,&lt;br /&gt;
    scalar 	me.property,&lt;br /&gt;
    scalar 	me.size,&lt;br /&gt;
    func 	me.mod_property(property_value),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The &amp;lt;tt&amp;gt;ScreenText.blank&amp;lt;/tt&amp;gt; does not create a recursion as it is added after the basic hash has been established -- at least this is what I believe... [[User:Hcc23|Hcc23]] 16:23, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.new&amp;lt;/tt&amp;gt; - The Constructor === &lt;br /&gt;
The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two main elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text (which is 32, what it defaults to if no other value is given); or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background. &lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the actual (multi-char) text of the element. Some limited constructor overloading can be used in order to generate different effects.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  #&lt;br /&gt;
  # 1st method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_text_verbose = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  var test_text_shorter = ScreenText.new(&amp;quot;Hello World!&amp;quot;,34); # does the same as the above as ScreenText[&amp;quot;WHITE&amp;quot;]==34&lt;br /&gt;
This would create screen text element containing the string &amp;lt;tt&amp;gt;Hello World!&amp;lt;/tt&amp;gt; and format it to be large white font. &lt;br /&gt;
&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  #&lt;br /&gt;
  # 2nd method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_prop_verbose = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  var test_prop_shorter = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],34); # result is identical to above  &lt;br /&gt;
This last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;/tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  var test_text_ = ScreenText.new(sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;)),ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
however, the benefit of the 2nd call method is that the ScreenText internally generates a record of the property (stored in &amp;lt;tt&amp;gt;me.property&amp;lt;/tt&amp;gt;) and as such allows to tie a listener to the screen text, such updating the screen text when the property changes. An example for this can be found in the [[Nasal CDU Framework]].&lt;br /&gt;
&lt;br /&gt;
The third way of instantiating a ScreenText allows a modification of the property via a function:&lt;br /&gt;
  #&lt;br /&gt;
  # 3rd method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_modprop_anonymous = ScreenText.new([&amp;quot;This runway is %f football fields long.&amp;quot;,&amp;quot;/some/where/runway-length-yards&amp;quot;,func(prop){return 0.01*prop;}],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  &lt;br /&gt;
  var divide_by_100 = func(value) { return 0.01*value;};&lt;br /&gt;
  var test_modprop_named = ScreenText.new([&amp;quot;This runway is %f football fields long.&amp;quot;,&amp;quot;/some/where/runway-length-yards&amp;quot;,divide_by_100],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
&lt;br /&gt;
What this does is comparable to this:&lt;br /&gt;
  ScreenText.new(sprintf(&amp;quot;This runway is %f football fields long.&amp;quot;,divide_by_100(getprop(&amp;quot;/some/where/runway-length-yards&amp;quot;))),ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
Again, but with the benefit of registering the function as well as the property and output format in the respective ''private'' variables &amp;lt;tt&amp;gt;me.mod_property&amp;lt;/tt&amp;gt;,&amp;lt;tt&amp;gt;me.property&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;me.format&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Example for a changing the style:'''&lt;br /&gt;
&lt;br /&gt;
A slight cheat (but a useful one) is incorporated when it comes to altering the style of a ScreenText element. One example for that would be toggle fields in the CDU in where the text essentially stays the same, but it's color (i.e. style) changes depending on a property. The third method of a constructor call can be used to achieve this, here exemplified by one of the before mentioned CDU toggle fields:&lt;br /&gt;
  var toggle_OnOff_on = func(decision_string) {&lt;br /&gt;
    if (decision_string==&amp;quot;ON&amp;quot;) {&lt;br /&gt;
      # &amp;quot;me&amp;quot; is the screen text object that calls this function...&lt;br /&gt;
      me.style = ScreenText[&amp;quot;GREEN&amp;quot;];&lt;br /&gt;
    } else {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;white&amp;quot;];&lt;br /&gt;
    };&lt;br /&gt;
    return &amp;quot;ON&amp;quot;;&lt;br /&gt;
  };&lt;br /&gt;
  &lt;br /&gt;
  var toggle_OnOff_off = func(decision_string) {&lt;br /&gt;
    if (decision_string==&amp;quot;OFF&amp;quot;) {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;GREEN&amp;quot;];&lt;br /&gt;
    } else {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;white&amp;quot;];&lt;br /&gt;
    }; &lt;br /&gt;
   return &amp;quot;OFF&amp;quot;;&lt;br /&gt;
  };&lt;br /&gt;
  &lt;br /&gt;
  var field_efisCtl = Field.new(ScreenText.new(&amp;quot;EFIS CTL&amp;quot;,ScreenText[&amp;quot;white&amp;quot;]),[&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_off]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;lt;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_on]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
  ],toggle_efisCtl);&lt;br /&gt;
&lt;br /&gt;
The important part here is the generation of the involved ScreenTexts. Note how the first and third indented ScreenTexts make use of the third form of calling the ScreenText constructor. However, when you check the property modification functions &amp;lt;tt&amp;gt;toggle_OnOff_on&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;toggle_OnOff_off&amp;lt;/tt&amp;gt;, you will find that they always return the same string (&amp;quot;ON&amp;quot; or &amp;quot;OFF&amp;quot;,resp.) which then is rendered in the &amp;lt;tt&amp;gt;sprintf()&amp;lt;/tt&amp;gt; fashion. However, making use of the &amp;lt;tt&amp;gt;me&amp;lt;/tt&amp;gt; Nasal element, both of these functions alter the style via &amp;lt;tt&amp;gt;me.style&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.sprint()&amp;lt;/tt&amp;gt; - Generating a String ===&lt;br /&gt;
&amp;lt;tt&amp;gt;.sprint()&amp;lt;/tt&amp;gt; does exactly that: it takes the associated &amp;lt;tt&amp;gt;me&amp;lt;/tt&amp;gt; screen text, runs it through the formatting process if necessary, and returns a Nasal scalar-type string.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.print()&amp;lt;/tt&amp;gt; - Print to the Console ===&lt;br /&gt;
This function simply wraps a Nasal &amp;lt;tt&amp;gt;print(...)&amp;lt;/tt&amp;gt; around the &amp;lt;tt&amp;gt;.sprint()&amp;lt;/tt&amp;gt;, effectively printing the screen text into the console. This function might be helpful for debugging purposes.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.update()&amp;lt;/tt&amp;gt; - Reparsing the ScreenText ===&lt;br /&gt;
This function has no apparent output or return value, but the internal variables, most importantly the &amp;lt;tt&amp;gt;.size&amp;lt;/tt&amp;gt; is updated. This might be necessary when SreenText elements are tied to properties which could result in a non-constant length of the ScreenText string.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ''Writing'' the Display Matrix ==&lt;br /&gt;
There are some other functions that actually do the ''writing'' into the display matrix, which lives in the property tree. (From there the XML takes it and renders it in the 3D world. But that happens without any necessary interactions.)&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;resetDisplayMatrix&amp;lt;/tt&amp;gt; - Erasing===&lt;br /&gt;
A call to this function via &lt;br /&gt;
  resetDisplayMatrix();&lt;br /&gt;
sets all elements in the display matrix to the &amp;lt;tt&amp;gt;ScreenText.blank&amp;lt;/tt&amp;gt;, i.e. an empty string with a style of &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;dumpDisplayMatrix&amp;lt;/tt&amp;gt; - Dump Content to Console===&lt;br /&gt;
A call to &lt;br /&gt;
  dumpDisplayMatrix(note=&amp;quot;Just testing what happens...&amp;quot;);&lt;br /&gt;
prints the current display matrix to the console, also putting the optional string &amp;lt;tt&amp;gt;note&amp;lt;/tt&amp;gt; above it, which might be helpful for debugging or identifying which call to &amp;lt;tt&amp;gt;dumpDisplayMatrix()&amp;lt;/tt&amp;gt; actually produced the output.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;writeDisplayMatrixText&amp;lt;/tt&amp;gt; - Print into the Display Matrix===&lt;br /&gt;
This is the actual ''print'' command for the display matrix. The full syntax of the function is &lt;br /&gt;
  writeDisplayMatrixText(row,col=0,element=nil,mode=nil)&lt;br /&gt;
&lt;br /&gt;
= Internal Representation of the Data =&lt;br /&gt;
&lt;br /&gt;
As the screen has a fixed resolution (governed by the &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; variables), internally the (0-indexed) screen is held in the FlightGear property tree. For the [[CDU]] the (0,0) cell is stored like this&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable holding the single character that should be displayed, i.e. representing the first layer of the display matrix. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal scalar-type variable (registering as a double in the property tree although it only requires integers), representing the formatting information, i.e. the second layer of the display matrix.&lt;br /&gt;
&lt;br /&gt;
The initial part of that property tree path, i.e. &amp;lt;tt&amp;gt;/instrumentation/cdu&amp;lt;/tt&amp;gt; is actually held in a variable named &amp;lt;tt&amp;gt;PROP&amp;lt;/tt&amp;gt; (which in case of the [[CDU]] is set to the before mentioned value), whereas the display matrix framework adds the &amp;lt;tt&amp;gt;./display/...&amp;lt;/tt&amp;gt; subtree.&lt;br /&gt;
This should allow for an easy inclusion of the framework into other instruments as long as that instrument is properly scoped, i.e. it provides its own (locally scoped) &amp;lt;tt&amp;gt;var PROP = &amp;quot;/where/ever&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Style Encoding ==&lt;br /&gt;
The style of the char to be displayed is encoded via a binary-style key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt; 17&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name that is aimed at capturing the features of that style,for example, &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt;. Each name is then mapped to a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
# The first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;).&lt;br /&gt;
# The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background. So &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; would be the name for a small font size, white font color, non-shaded formatting, whereas &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt; would be standing for a large font size, cyan font color, shaded background formatting.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet correctly implemented but the framework provides an internal hack to make use of some of the formatting information. [[User:Hcc23|Hcc23]] 09:50, 10 May 2011 (EDT) &lt;br /&gt;
&lt;br /&gt;
== The XML Style Interface ==&lt;br /&gt;
In order to make use of the Nasal-maintained data, the 3D model representing the screen has to access the data in the property tree and render it according to the style set there.&lt;br /&gt;
&lt;br /&gt;
This is accomplished via two pieces of code:&lt;br /&gt;
# the fairly generic &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt;&lt;br /&gt;
# a fairly specific and elaborate section in the model specific XML (in case of the [[CDU]] that would be &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== The XML Template for Display Matrix Text ===&lt;br /&gt;
The &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt; essentially provides a template for the creation of an OSGText element, just as other text that is rendered in the the 3D cockpit. The file is comprised of a few sub-sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  &amp;lt;PropertyList&amp;gt;&lt;br /&gt;
    &amp;lt;params&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/params&amp;gt;&lt;br /&gt;
    &amp;lt;text&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/text&amp;gt;&lt;br /&gt;
    &amp;lt;animation&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/animation&amp;gt;&lt;br /&gt;
  &amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; section provides a place for all the elements that need to be altered/adapted for the individual characters, i.e. whenever the template is actually used, the values in this section (and if possible this section only) should be changed. More on that later...&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;text&amp;gt;...&amp;lt;/text&amp;gt;&amp;lt;/tt&amp;gt; section provides the actual ''model'' for the OSGText. It is a fairly complete set of settings from &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;animation&amp;gt;...&amp;lt;/animation&amp;gt;&amp;lt;/tt&amp;gt; section then alters the rendering of the text, particularly it provides for a ''material'', i.e. the color. This section ''should'' hence do the translation from the different styles into the corresponding difference in the rendering. (Which, AFAIK, should be possible through different materials [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)).&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I mentioned earlier that I needed to build in a cheat. Well, it is in the animations section. For some reason I couldn't wrap my head around how to change the color of an animation based upon a variable in the Nasal scope, i.e. a condition like &amp;lt;tt&amp;gt;IF A=1 DO...&amp;lt;/tt&amp;gt;. So I made the display matrix framework put in some extra variables which I did manage to poll, using several animations which get enabled based on mutually exclusive conditions. One drawback (other than it seriously looking lousy) is that I couldn't manage to use that cheat to change the font size. I assume that this is due to the fact that the size is set outside the animation and directly in the text block... So ANY hint on how to generate the text in different sizes (using XML) would be greatly appreciated. [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== The XML ''Instantiation'' of Display Matrix Text ===&lt;br /&gt;
&lt;br /&gt;
So the real work happens to happen inside the CDU's 3D model XML, &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;. In that file, each an every (r,c) cell of the display matrix gets to be a separate model (yes, that means ton's of XML code...). Here is how one such instance looks like:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  			&amp;lt;style&amp;gt;/instrumentation/cdu/display/row-0/col-0/style&amp;lt;/style&amp;gt;&lt;br /&gt;
  			&amp;lt;font-color&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-color&amp;lt;/font-color&amp;gt;&lt;br /&gt;
  			&amp;lt;font-size-m&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-size-m&amp;lt;/font-size-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What happens here is also two-fold:&lt;br /&gt;
# First, the relevant sections in the &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; block get overwritten. &lt;br /&gt;
# Second, the model get's (re-)located at/to the correct position.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Here again traces of my cheat are visible. In theory one wouldn't need the &amp;lt;tt&amp;gt;font-color&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;font-size&amp;lt;/tt&amp;gt; variables, as this information is already encoded in the &amp;lt;tt&amp;gt;style&amp;lt;/tt&amp;gt; variable. However, I couldn't get that to work... [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
As this XML is extremely repetitive, a MATLAB script was used to ''autocode'' this section. (The script below will output a file, &amp;lt;tt&amp;gt;FILENAME&amp;lt;/tt&amp;gt;, containing all the XML which then could be copy-pasted into the model's XML.):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
          &lt;br /&gt;
          charPath  = sprintf('/instrumentation/cdu/display/row-%d/col-%d',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;style&amp;gt;%s&amp;lt;/style&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-color&amp;gt;%s&amp;lt;/font-color&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-size-m&amp;gt;%s&amp;lt;/font-size-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          [charPath '/char'],...&lt;br /&gt;
          [charPath '/style'],...&lt;br /&gt;
          [charPath '/font-color'],...&lt;br /&gt;
          [charPath '/font-size-m'],...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31586</id>
		<title>Nasal Display Matrix Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31586"/>
		<updated>2011-05-10T20:51:59Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Nasal Code to Generate Display Matrix Text */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
For the development of a Nasal-based [[CDU]] a main hurdle was the replication of the ''screen'' of the [[CDU]]. This Nasal code framework was created to achieve this. Hence, a lot of usage examples can be found in the sources related to the [[CDU]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Type of Replicated Display =&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The CDU utilizes a display matrix. Shown is an early version of page where the text bounding boxes have been enabled for the purpose of better showing the matrix style layout.]]&lt;br /&gt;
&lt;br /&gt;
This framework can replicate any display that uses a fixed row-and-column type screen layout, i.e. a display that has a fixed number of rows (e.g., &amp;lt;tt&amp;gt;var ROWS = 14;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;) and a fixed number of columns (e.g., &amp;lt;tt&amp;gt;var COLS = 24;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;), where each of these &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; cells holds exactly one character, resulting in a fixed-spaced font (like most console type fonts).&lt;br /&gt;
&lt;br /&gt;
Furthermore, each cell also holds the formatting information of that cell, i.e. the information on font, color, size, etc.&lt;br /&gt;
&lt;br /&gt;
Overall, such a display can be thought of as a &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt;x2 matrix (hence the name of the framework) where the first layer (i.e. all (r,c,1) elements) holds the character information for the cell (r,c) and the the second layer (i.e. all (r,c,2) elements) holds the formatting information.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Although generic, the rest of this wiki page will heavily use examples from the [[CDU]] - but the concept of the display matrix can be used for other screen like instruments as well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Nasal Code to Generate Display Matrix Text =&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;. Including this fiel into your projects should be sufficient to allow you to use a display matrix.&lt;br /&gt;
&lt;br /&gt;
== ScreenText ==&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields of the [[CDU]]. Several elements can be concatenated in a single line by stacking them in a vector, allowing for a more complex formatting of the text. Here is a brake-down of the Nasal class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ScreenText = {&lt;br /&gt;
    # the actual styles name-to-value hash-map&lt;br /&gt;
    # skipped, see above for details&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Static/Public&amp;quot;	&lt;br /&gt;
    func 	new(t,s=32,ptp=nil),&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	sprint(),&lt;br /&gt;
    func 	print(),&lt;br /&gt;
    func 	update(),&lt;br /&gt;
    &lt;br /&gt;
    (ScreenText) blank,    &lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    scalar 	me.style,&lt;br /&gt;
    scalar 	me.text,&lt;br /&gt;
    scalar 	me.property,&lt;br /&gt;
    scalar 	me.size,&lt;br /&gt;
    func 	me.mod_property(property_value),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The &amp;lt;tt&amp;gt;ScreenText.blank&amp;lt;/tt&amp;gt; does not create a recursion as it is added after the basic hash has been established -- at least this is what I believe... [[User:Hcc23|Hcc23]] 16:23, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.new&amp;lt;/tt&amp;gt; - The Constructor === &lt;br /&gt;
The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two main elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text (which is 32, what it defaults to if no other value is given); or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background. &lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the actual (multi-char) text of the element. Some limited constructor overloading can be used in order to generate different effects.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  #&lt;br /&gt;
  # 1st method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_text_verbose = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  var test_text_shorter = ScreenText.new(&amp;quot;Hello World!&amp;quot;,34); # does the same as the above as ScreenText[&amp;quot;WHITE&amp;quot;]==34&lt;br /&gt;
This would create screen text element containing the string &amp;lt;tt&amp;gt;Hello World!&amp;lt;/tt&amp;gt; and format it to be large white font. &lt;br /&gt;
&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  #&lt;br /&gt;
  # 2nd method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_prop_verbose = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  var test_prop_shorter = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],34); # result is identical to above  &lt;br /&gt;
This last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;/tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  var test_text_ = ScreenText.new(sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;)),ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
however, the benefit of the 2nd call method is that the ScreenText internally generates a record of the property (stored in &amp;lt;tt&amp;gt;me.property&amp;lt;/tt&amp;gt;) and as such allows to tie a listener to the screen text, such updating the screen text when the property changes. An example for this can be found in the [[Nasal CDU Framework]].&lt;br /&gt;
&lt;br /&gt;
The third way of instantiating a ScreenText allows a modification of the property via a function:&lt;br /&gt;
  #&lt;br /&gt;
  # 3rd method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_modprop_anonymous = ScreenText.new([&amp;quot;This runway is %f football fields long.&amp;quot;,&amp;quot;/some/where/runway-length-yards&amp;quot;,func(prop){return 0.01*prop;}],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  &lt;br /&gt;
  var divide_by_100 = func(value) { return 0.01*value;};&lt;br /&gt;
  var test_modprop_named = ScreenText.new([&amp;quot;This runway is %f football fields long.&amp;quot;,&amp;quot;/some/where/runway-length-yards&amp;quot;,divide_by_100],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
&lt;br /&gt;
What this does is comparable to this:&lt;br /&gt;
  ScreenText.new(sprintf(&amp;quot;This runway is %f football fields long.&amp;quot;,divide_by_100(getprop(&amp;quot;/some/where/runway-length-yards&amp;quot;))),ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
Again, but with the benefit of registering the function as well as the property and output format in the respective ''private'' variables &amp;lt;tt&amp;gt;me.mod_property&amp;lt;/tt&amp;gt;,&amp;lt;tt&amp;gt;me.property&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;me.format&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Example for a changing the style:'''&lt;br /&gt;
&lt;br /&gt;
A slight cheat (but a useful one) is incorporated when it comes to altering the style of a ScreenText element. One example for that would be toggle fields in the CDU in where the text essentially stays the same, but it's color (i.e. style) changes depending on a property. The third method of a constructor call can be used to achieve this, here exemplified by one of the before mentioned CDU toggle fields:&lt;br /&gt;
  var toggle_OnOff_on = func(decision_string) {&lt;br /&gt;
    if (decision_string==&amp;quot;ON&amp;quot;) {&lt;br /&gt;
      # &amp;quot;me&amp;quot; is the screen text object that calls this function...&lt;br /&gt;
      me.style = ScreenText[&amp;quot;GREEN&amp;quot;];&lt;br /&gt;
    } else {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;white&amp;quot;];&lt;br /&gt;
    };&lt;br /&gt;
    return &amp;quot;ON&amp;quot;;&lt;br /&gt;
  };&lt;br /&gt;
  &lt;br /&gt;
  var toggle_OnOff_off = func(decision_string) {&lt;br /&gt;
    if (decision_string==&amp;quot;OFF&amp;quot;) {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;GREEN&amp;quot;];&lt;br /&gt;
    } else {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;white&amp;quot;];&lt;br /&gt;
    }; &lt;br /&gt;
   return &amp;quot;OFF&amp;quot;;&lt;br /&gt;
  };&lt;br /&gt;
  &lt;br /&gt;
  var field_efisCtl = Field.new(ScreenText.new(&amp;quot;EFIS CTL&amp;quot;,ScreenText[&amp;quot;white&amp;quot;]),[&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_off]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;lt;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_on]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
  ],toggle_efisCtl);&lt;br /&gt;
&lt;br /&gt;
The important part here is the generation of the involved ScreenTexts. Note how the first and third ScreenText make use of the third form of calling the ScreenText constructor. However, when you check the property modification functions &amp;lt;tt&amp;gt;toggle_OnOff_on&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;toggle_OnOff_off&amp;lt;/tt&amp;gt;, you will find that they always return the same string (&amp;quot;ON&amp;quot; or &amp;quot;OFF&amp;quot;,resp.) which then is rendered in the &amp;lt;tt&amp;gt;sprintf()&amp;lt;/tt&amp;gt; fashion. However, making use of the &amp;lt;tt&amp;gt;me&amp;lt;/tt&amp;gt; Nasal element, both of these functions alter the style via &amp;lt;tt&amp;gt;me.style&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.sprint()&amp;lt;/tt&amp;gt; - Generating a String ===&lt;br /&gt;
&amp;lt;tt&amp;gt;.sprint()&amp;lt;/tt&amp;gt; does exactly that: it takes the associated &amp;lt;tt&amp;gt;me&amp;lt;/tt&amp;gt; screen text, runs it through the formatting process if necessary, and returns a Nasal scalar-type string.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.print()&amp;lt;/tt&amp;gt; - Print to the Console ===&lt;br /&gt;
This function simply wraps a Nasal &amp;lt;tt&amp;gt;print(...)&amp;lt;/tt&amp;gt; around the &amp;lt;tt&amp;gt;.sprint()&amp;lt;/tt&amp;gt;, effectively printing the screen text into the console. This function might be helpful for debugging purposes.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.update()&amp;lt;/tt&amp;gt; - Reparsing the ScreenText ===&lt;br /&gt;
This function has no apparent output or return value, but the internal variables, most importantly the &amp;lt;tt&amp;gt;.size&amp;lt;/tt&amp;gt; is updated. This might be necessary when SreenText elements are tied to properties which could result in a non-constant length of the ScreenText string.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ''Writing'' the Display Matrix ==&lt;br /&gt;
There are some other functions that actually do the ''writing'' into the display matrix, which lives in the property tree. (From there the XML takes it and renders it in the 3D world. But that happens without any necessary interactions.)&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;resetDisplayMatrix&amp;lt;/tt&amp;gt; - Erasing===&lt;br /&gt;
A call to this function via &lt;br /&gt;
  resetDisplayMatrix();&lt;br /&gt;
sets all elements in the display matrix to the &amp;lt;tt&amp;gt;ScreenText.blank&amp;lt;/tt&amp;gt;, i.e. an empty string with a style of &amp;quot;off&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;dumpDisplayMatrix&amp;lt;/tt&amp;gt; - Dump Content to Console===&lt;br /&gt;
A call to &lt;br /&gt;
  dumpDisplayMatrix(note=&amp;quot;Just testing what happens...&amp;quot;);&lt;br /&gt;
prints the current display matrix to the console, also putting the optional string &amp;lt;tt&amp;gt;note&amp;lt;/tt&amp;gt; above it, which might be helpful for debugging or identifying which call to &amp;lt;tt&amp;gt;dumpDisplayMatrix()&amp;lt;/tt&amp;gt; actually produced the output.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;writeDisplayMatrixText&amp;lt;/tt&amp;gt; - Print into the Display Matrix===&lt;br /&gt;
This is the actual ''print'' command for the display matrix. The full syntax of the function is &lt;br /&gt;
  writeDisplayMatrixText(row,col=0,element=nil,mode=nil)&lt;br /&gt;
&lt;br /&gt;
= Internal Representation of the Data =&lt;br /&gt;
&lt;br /&gt;
As the screen has a fixed resolution (governed by the &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; variables), internally the (0-indexed) screen is held in the FlightGear property tree. For the [[CDU]] the (0,0) cell is stored like this&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable holding the single character that should be displayed, i.e. representing the first layer of the display matrix. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal scalar-type variable (registering as a double in the property tree although it only requires integers), representing the formatting information, i.e. the second layer of the display matrix.&lt;br /&gt;
&lt;br /&gt;
The initial part of that property tree path, i.e. &amp;lt;tt&amp;gt;/instrumentation/cdu&amp;lt;/tt&amp;gt; is actually held in a variable named &amp;lt;tt&amp;gt;PROP&amp;lt;/tt&amp;gt; (which in case of the [[CDU]] is set to the before mentioned value), whereas the display matrix framework adds the &amp;lt;tt&amp;gt;./display/...&amp;lt;/tt&amp;gt; subtree.&lt;br /&gt;
This should allow for an easy inclusion of the framework into other instruments as long as that instrument is properly scoped, i.e. it provides its own (locally scoped) &amp;lt;tt&amp;gt;var PROP = &amp;quot;/where/ever&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Style Encoding ==&lt;br /&gt;
The style of the char to be displayed is encoded via a binary-style key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt; 17&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name that is aimed at capturing the features of that style,for example, &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt;. Each name is then mapped to a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
# The first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;).&lt;br /&gt;
# The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background. So &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; would be the name for a small font size, white font color, non-shaded formatting, whereas &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt; would be standing for a large font size, cyan font color, shaded background formatting.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet correctly implemented but the framework provides an internal hack to make use of some of the formatting information. [[User:Hcc23|Hcc23]] 09:50, 10 May 2011 (EDT) &lt;br /&gt;
&lt;br /&gt;
== The XML Style Interface ==&lt;br /&gt;
In order to make use of the Nasal-maintained data, the 3D model representing the screen has to access the data in the property tree and render it according to the style set there.&lt;br /&gt;
&lt;br /&gt;
This is accomplished via two pieces of code:&lt;br /&gt;
# the fairly generic &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt;&lt;br /&gt;
# a fairly specific and elaborate section in the model specific XML (in case of the [[CDU]] that would be &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== The XML Template for Display Matrix Text ===&lt;br /&gt;
The &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt; essentially provides a template for the creation of an OSGText element, just as other text that is rendered in the the 3D cockpit. The file is comprised of a few sub-sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  &amp;lt;PropertyList&amp;gt;&lt;br /&gt;
    &amp;lt;params&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/params&amp;gt;&lt;br /&gt;
    &amp;lt;text&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/text&amp;gt;&lt;br /&gt;
    &amp;lt;animation&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/animation&amp;gt;&lt;br /&gt;
  &amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; section provides a place for all the elements that need to be altered/adapted for the individual characters, i.e. whenever the template is actually used, the values in this section (and if possible this section only) should be changed. More on that later...&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;text&amp;gt;...&amp;lt;/text&amp;gt;&amp;lt;/tt&amp;gt; section provides the actual ''model'' for the OSGText. It is a fairly complete set of settings from &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;animation&amp;gt;...&amp;lt;/animation&amp;gt;&amp;lt;/tt&amp;gt; section then alters the rendering of the text, particularly it provides for a ''material'', i.e. the color. This section ''should'' hence do the translation from the different styles into the corresponding difference in the rendering. (Which, AFAIK, should be possible through different materials [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)).&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I mentioned earlier that I needed to build in a cheat. Well, it is in the animations section. For some reason I couldn't wrap my head around how to change the color of an animation based upon a variable in the Nasal scope, i.e. a condition like &amp;lt;tt&amp;gt;IF A=1 DO...&amp;lt;/tt&amp;gt;. So I made the display matrix framework put in some extra variables which I did manage to poll, using several animations which get enabled based on mutually exclusive conditions. One drawback (other than it seriously looking lousy) is that I couldn't manage to use that cheat to change the font size. I assume that this is due to the fact that the size is set outside the animation and directly in the text block... So ANY hint on how to generate the text in different sizes (using XML) would be greatly appreciated. [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== The XML ''Instantiation'' of Display Matrix Text ===&lt;br /&gt;
&lt;br /&gt;
So the real work happens to happen inside the CDU's 3D model XML, &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;. In that file, each an every (r,c) cell of the display matrix gets to be a separate model (yes, that means ton's of XML code...). Here is how one such instance looks like:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  			&amp;lt;style&amp;gt;/instrumentation/cdu/display/row-0/col-0/style&amp;lt;/style&amp;gt;&lt;br /&gt;
  			&amp;lt;font-color&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-color&amp;lt;/font-color&amp;gt;&lt;br /&gt;
  			&amp;lt;font-size-m&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-size-m&amp;lt;/font-size-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What happens here is also two-fold:&lt;br /&gt;
# First, the relevant sections in the &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; block get overwritten. &lt;br /&gt;
# Second, the model get's (re-)located at/to the correct position.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Here again traces of my cheat are visible. In theory one wouldn't need the &amp;lt;tt&amp;gt;font-color&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;font-size&amp;lt;/tt&amp;gt; variables, as this information is already encoded in the &amp;lt;tt&amp;gt;style&amp;lt;/tt&amp;gt; variable. However, I couldn't get that to work... [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
As this XML is extremely repetitive, a MATLAB script was used to ''autocode'' this section. (The script below will output a file, &amp;lt;tt&amp;gt;FILENAME&amp;lt;/tt&amp;gt;, containing all the XML which then could be copy-pasted into the model's XML.):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
          &lt;br /&gt;
          charPath  = sprintf('/instrumentation/cdu/display/row-%d/col-%d',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;style&amp;gt;%s&amp;lt;/style&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-color&amp;gt;%s&amp;lt;/font-color&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-size-m&amp;gt;%s&amp;lt;/font-size-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          [charPath '/char'],...&lt;br /&gt;
          [charPath '/style'],...&lt;br /&gt;
          [charPath '/font-color'],...&lt;br /&gt;
          [charPath '/font-size-m'],...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31585</id>
		<title>Nasal Display Matrix Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31585"/>
		<updated>2011-05-10T20:41:09Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* ScreenText */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
For the development of a Nasal-based [[CDU]] a main hurdle was the replication of the ''screen'' of the [[CDU]]. This Nasal code framework was created to achieve this. Hence, a lot of usage examples can be found in the sources related to the [[CDU]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Type of Replicated Display =&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The CDU utilizes a display matrix. Shown is an early version of page where the text bounding boxes have been enabled for the purpose of better showing the matrix style layout.]]&lt;br /&gt;
&lt;br /&gt;
This framework can replicate any display that uses a fixed row-and-column type screen layout, i.e. a display that has a fixed number of rows (e.g., &amp;lt;tt&amp;gt;var ROWS = 14;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;) and a fixed number of columns (e.g., &amp;lt;tt&amp;gt;var COLS = 24;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;), where each of these &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; cells holds exactly one character, resulting in a fixed-spaced font (like most console type fonts).&lt;br /&gt;
&lt;br /&gt;
Furthermore, each cell also holds the formatting information of that cell, i.e. the information on font, color, size, etc.&lt;br /&gt;
&lt;br /&gt;
Overall, such a display can be thought of as a &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt;x2 matrix (hence the name of the framework) where the first layer (i.e. all (r,c,1) elements) holds the character information for the cell (r,c) and the the second layer (i.e. all (r,c,2) elements) holds the formatting information.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Although generic, the rest of this wiki page will heavily use examples from the [[CDU]] - but the concept of the display matrix can be used for other screen like instruments as well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Nasal Code to Generate Display Matrix Text =&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;. Including this fiel into your projects should be sufficient to allow you to use a display matrix.&lt;br /&gt;
&lt;br /&gt;
== ScreenText ==&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields of the [[CDU]]. Several elements can be concatenated in a single line by stacking them in a vector, allowing for a more complex formatting of the text. Here is a brake-down of the Nasal class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ScreenText = {&lt;br /&gt;
    # the actual styles name-to-value hash-map&lt;br /&gt;
    # skipped, see above for details&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Static/Public&amp;quot;	&lt;br /&gt;
    func 	new(t,s=32,ptp=nil),&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	sprint(),&lt;br /&gt;
    func 	print(),&lt;br /&gt;
    func 	update(),&lt;br /&gt;
    &lt;br /&gt;
    (ScreenText) blank,    &lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    scalar 	me.style,&lt;br /&gt;
    scalar 	me.text,&lt;br /&gt;
    scalar 	me.property,&lt;br /&gt;
    scalar 	me.size,&lt;br /&gt;
    func 	me.mod_property(property_value),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The &amp;lt;tt&amp;gt;ScreenText.blank&amp;lt;/tt&amp;gt; does not create a recursion as it is added after the basic hash has been established -- at least this is what I believe... [[User:Hcc23|Hcc23]] 16:23, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.new&amp;lt;/tt&amp;gt; - The Constructor === &lt;br /&gt;
The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two main elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text (which is 32, what it defaults to if no other value is given); or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background. &lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the actual (multi-char) text of the element. Some limited constructor overloading can be used in order to generate different effects.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  #&lt;br /&gt;
  # 1st method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_text_verbose = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  var test_text_shorter = ScreenText.new(&amp;quot;Hello World!&amp;quot;,34); # does the same as the above as ScreenText[&amp;quot;WHITE&amp;quot;]==34&lt;br /&gt;
This would create screen text element containing the string &amp;lt;tt&amp;gt;Hello World!&amp;lt;/tt&amp;gt; and format it to be large white font. &lt;br /&gt;
&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  #&lt;br /&gt;
  # 2nd method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_prop_verbose = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  var test_prop_shorter = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],34); # result is identical to above  &lt;br /&gt;
This last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;/tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  var test_text_ = ScreenText.new(sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;)),ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
however, the benefit of the 2nd call method is that the ScreenText internally generates a record of the property (stored in &amp;lt;tt&amp;gt;me.property&amp;lt;/tt&amp;gt;) and as such allows to tie a listener to the screen text, such updating the screen text when the property changes. An example for this can be found in the [[Nasal CDU Framework]].&lt;br /&gt;
&lt;br /&gt;
The third way of instantiating a ScreenText allows a modification of the property via a function:&lt;br /&gt;
  #&lt;br /&gt;
  # 3rd method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_modprop_anonymous = ScreenText.new([&amp;quot;This runway is %f football fields long.&amp;quot;,&amp;quot;/some/where/runway-length-yards&amp;quot;,func(prop){return 0.01*prop;}],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  &lt;br /&gt;
  var divide_by_100 = func(value) { return 0.01*value;};&lt;br /&gt;
  var test_modprop_named = ScreenText.new([&amp;quot;This runway is %f football fields long.&amp;quot;,&amp;quot;/some/where/runway-length-yards&amp;quot;,divide_by_100],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
&lt;br /&gt;
What this does is comparable to this:&lt;br /&gt;
  ScreenText.new(sprintf(&amp;quot;This runway is %f football fields long.&amp;quot;,divide_by_100(getprop(&amp;quot;/some/where/runway-length-yards&amp;quot;))),ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
Again, but with the benefit of registering the function as well as the property and output format in the respective ''private'' variables &amp;lt;tt&amp;gt;me.mod_property&amp;lt;/tt&amp;gt;,&amp;lt;tt&amp;gt;me.property&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;me.format&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Example for a changing the style:'''&lt;br /&gt;
&lt;br /&gt;
A slight cheat (but a useful one) is incorporated when it comes to altering the style of a ScreenText element. One example for that would be toggle fields in the CDU in where the text essentially stays the same, but it's color (i.e. style) changes depending on a property. The third method of a constructor call can be used to achieve this, here exemplified by one of the before mentioned CDU toggle fields:&lt;br /&gt;
  var toggle_OnOff_on = func(decision_string) {&lt;br /&gt;
    if (decision_string==&amp;quot;ON&amp;quot;) {&lt;br /&gt;
      # &amp;quot;me&amp;quot; is the screen text object that calls this function...&lt;br /&gt;
      me.style = ScreenText[&amp;quot;GREEN&amp;quot;];&lt;br /&gt;
    } else {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;white&amp;quot;];&lt;br /&gt;
    };&lt;br /&gt;
    return &amp;quot;ON&amp;quot;;&lt;br /&gt;
  };&lt;br /&gt;
  &lt;br /&gt;
  var toggle_OnOff_off = func(decision_string) {&lt;br /&gt;
    if (decision_string==&amp;quot;OFF&amp;quot;) {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;GREEN&amp;quot;];&lt;br /&gt;
    } else {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;white&amp;quot;];&lt;br /&gt;
    }; &lt;br /&gt;
   return &amp;quot;OFF&amp;quot;;&lt;br /&gt;
  };&lt;br /&gt;
  &lt;br /&gt;
  var field_efisCtl = Field.new(ScreenText.new(&amp;quot;EFIS CTL&amp;quot;,ScreenText[&amp;quot;white&amp;quot;]),[&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_off]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;lt;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_on]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
  ],toggle_efisCtl);&lt;br /&gt;
&lt;br /&gt;
The important part here is the generation of the involved ScreenTexts. Note how the first and third ScreenText make use of the third form of calling the ScreenText constructor. However, when you check the property modification functions &amp;lt;tt&amp;gt;toggle_OnOff_on&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;toggle_OnOff_off&amp;lt;/tt&amp;gt;, you will find that they always return the same string (&amp;quot;ON&amp;quot; or &amp;quot;OFF&amp;quot;,resp.) which then is rendered in the &amp;lt;tt&amp;gt;sprintf()&amp;lt;/tt&amp;gt; fashion. However, making use of the &amp;lt;tt&amp;gt;me&amp;lt;/tt&amp;gt; Nasal element, both of these functions alter the style via &amp;lt;tt&amp;gt;me.style&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.sprint()&amp;lt;/tt&amp;gt; - Generating a String ===&lt;br /&gt;
&amp;lt;tt&amp;gt;.sprint()&amp;lt;/tt&amp;gt; does exactly that: it takes the associated &amp;lt;tt&amp;gt;me&amp;lt;/tt&amp;gt; screen text, runs it through the formatting process if necessary, and returns a Nasal scalar-type string.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.print()&amp;lt;/tt&amp;gt; - Print to the Console ===&lt;br /&gt;
This function simply wraps a Nasal &amp;lt;tt&amp;gt;print(...)&amp;lt;/tt&amp;gt; around the &amp;lt;tt&amp;gt;.sprint()&amp;lt;/tt&amp;gt;, effectively printing the screen text into the console. This function might be helpful for debugging purposes.&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.update()&amp;lt;/tt&amp;gt; - Reparsing the ScreenText ===&lt;br /&gt;
This function has no apparent output or return value, but the internal variables, most importantly the &amp;lt;tt&amp;gt;.size&amp;lt;/tt&amp;gt; is updated. This might be necessary when SreenText elements are tied to properties which could result in a non-constant length of the ScreenText string.&lt;br /&gt;
&lt;br /&gt;
= Internal Representation of the Data =&lt;br /&gt;
&lt;br /&gt;
As the screen has a fixed resolution (governed by the &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; variables), internally the (0-indexed) screen is held in the FlightGear property tree. For the [[CDU]] the (0,0) cell is stored like this&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable holding the single character that should be displayed, i.e. representing the first layer of the display matrix. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal scalar-type variable (registering as a double in the property tree although it only requires integers), representing the formatting information, i.e. the second layer of the display matrix.&lt;br /&gt;
&lt;br /&gt;
The initial part of that property tree path, i.e. &amp;lt;tt&amp;gt;/instrumentation/cdu&amp;lt;/tt&amp;gt; is actually held in a variable named &amp;lt;tt&amp;gt;PROP&amp;lt;/tt&amp;gt; (which in case of the [[CDU]] is set to the before mentioned value), whereas the display matrix framework adds the &amp;lt;tt&amp;gt;./display/...&amp;lt;/tt&amp;gt; subtree.&lt;br /&gt;
This should allow for an easy inclusion of the framework into other instruments as long as that instrument is properly scoped, i.e. it provides its own (locally scoped) &amp;lt;tt&amp;gt;var PROP = &amp;quot;/where/ever&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Style Encoding ==&lt;br /&gt;
The style of the char to be displayed is encoded via a binary-style key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt; 17&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name that is aimed at capturing the features of that style,for example, &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt;. Each name is then mapped to a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
# The first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;).&lt;br /&gt;
# The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background. So &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; would be the name for a small font size, white font color, non-shaded formatting, whereas &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt; would be standing for a large font size, cyan font color, shaded background formatting.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet correctly implemented but the framework provides an internal hack to make use of some of the formatting information. [[User:Hcc23|Hcc23]] 09:50, 10 May 2011 (EDT) &lt;br /&gt;
&lt;br /&gt;
== The XML Style Interface ==&lt;br /&gt;
In order to make use of the Nasal-maintained data, the 3D model representing the screen has to access the data in the property tree and render it according to the style set there.&lt;br /&gt;
&lt;br /&gt;
This is accomplished via two pieces of code:&lt;br /&gt;
# the fairly generic &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt;&lt;br /&gt;
# a fairly specific and elaborate section in the model specific XML (in case of the [[CDU]] that would be &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== The XML Template for Display Matrix Text ===&lt;br /&gt;
The &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt; essentially provides a template for the creation of an OSGText element, just as other text that is rendered in the the 3D cockpit. The file is comprised of a few sub-sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  &amp;lt;PropertyList&amp;gt;&lt;br /&gt;
    &amp;lt;params&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/params&amp;gt;&lt;br /&gt;
    &amp;lt;text&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/text&amp;gt;&lt;br /&gt;
    &amp;lt;animation&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/animation&amp;gt;&lt;br /&gt;
  &amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; section provides a place for all the elements that need to be altered/adapted for the individual characters, i.e. whenever the template is actually used, the values in this section (and if possible this section only) should be changed. More on that later...&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;text&amp;gt;...&amp;lt;/text&amp;gt;&amp;lt;/tt&amp;gt; section provides the actual ''model'' for the OSGText. It is a fairly complete set of settings from &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;animation&amp;gt;...&amp;lt;/animation&amp;gt;&amp;lt;/tt&amp;gt; section then alters the rendering of the text, particularly it provides for a ''material'', i.e. the color. This section ''should'' hence do the translation from the different styles into the corresponding difference in the rendering. (Which, AFAIK, should be possible through different materials [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)).&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I mentioned earlier that I needed to build in a cheat. Well, it is in the animations section. For some reason I couldn't wrap my head around how to change the color of an animation based upon a variable in the Nasal scope, i.e. a condition like &amp;lt;tt&amp;gt;IF A=1 DO...&amp;lt;/tt&amp;gt;. So I made the display matrix framework put in some extra variables which I did manage to poll, using several animations which get enabled based on mutually exclusive conditions. One drawback (other than it seriously looking lousy) is that I couldn't manage to use that cheat to change the font size. I assume that this is due to the fact that the size is set outside the animation and directly in the text block... So ANY hint on how to generate the text in different sizes (using XML) would be greatly appreciated. [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== The XML ''Instantiation'' of Display Matrix Text ===&lt;br /&gt;
&lt;br /&gt;
So the real work happens to happen inside the CDU's 3D model XML, &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;. In that file, each an every (r,c) cell of the display matrix gets to be a separate model (yes, that means ton's of XML code...). Here is how one such instance looks like:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  			&amp;lt;style&amp;gt;/instrumentation/cdu/display/row-0/col-0/style&amp;lt;/style&amp;gt;&lt;br /&gt;
  			&amp;lt;font-color&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-color&amp;lt;/font-color&amp;gt;&lt;br /&gt;
  			&amp;lt;font-size-m&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-size-m&amp;lt;/font-size-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What happens here is also two-fold:&lt;br /&gt;
# First, the relevant sections in the &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; block get overwritten. &lt;br /&gt;
# Second, the model get's (re-)located at/to the correct position.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Here again traces of my cheat are visible. In theory one wouldn't need the &amp;lt;tt&amp;gt;font-color&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;font-size&amp;lt;/tt&amp;gt; variables, as this information is already encoded in the &amp;lt;tt&amp;gt;style&amp;lt;/tt&amp;gt; variable. However, I couldn't get that to work... [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
As this XML is extremely repetitive, a MATLAB script was used to ''autocode'' this section. (The script below will output a file, &amp;lt;tt&amp;gt;FILENAME&amp;lt;/tt&amp;gt;, containing all the XML which then could be copy-pasted into the model's XML.):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
          &lt;br /&gt;
          charPath  = sprintf('/instrumentation/cdu/display/row-%d/col-%d',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;style&amp;gt;%s&amp;lt;/style&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-color&amp;gt;%s&amp;lt;/font-color&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-size-m&amp;gt;%s&amp;lt;/font-size-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          [charPath '/char'],...&lt;br /&gt;
          [charPath '/style'],...&lt;br /&gt;
          [charPath '/font-color'],...&lt;br /&gt;
          [charPath '/font-size-m'],...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31584</id>
		<title>Nasal Display Matrix Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31584"/>
		<updated>2011-05-10T20:23:15Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* ScreenText */  elaborate on using the constructor&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
For the development of a Nasal-based [[CDU]] a main hurdle was the replication of the ''screen'' of the [[CDU]]. This Nasal code framework was created to achieve this. Hence, a lot of usage examples can be found in the sources related to the [[CDU]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Type of Replicated Display =&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The CDU utilizes a display matrix. Shown is an early version of page where the text bounding boxes have been enabled for the purpose of better showing the matrix style layout.]]&lt;br /&gt;
&lt;br /&gt;
This framework can replicate any display that uses a fixed row-and-column type screen layout, i.e. a display that has a fixed number of rows (e.g., &amp;lt;tt&amp;gt;var ROWS = 14;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;) and a fixed number of columns (e.g., &amp;lt;tt&amp;gt;var COLS = 24;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;), where each of these &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; cells holds exactly one character, resulting in a fixed-spaced font (like most console type fonts).&lt;br /&gt;
&lt;br /&gt;
Furthermore, each cell also holds the formatting information of that cell, i.e. the information on font, color, size, etc.&lt;br /&gt;
&lt;br /&gt;
Overall, such a display can be thought of as a &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt;x2 matrix (hence the name of the framework) where the first layer (i.e. all (r,c,1) elements) holds the character information for the cell (r,c) and the the second layer (i.e. all (r,c,2) elements) holds the formatting information.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Although generic, the rest of this wiki page will heavily use examples from the [[CDU]] - but the concept of the display matrix can be used for other screen like instruments as well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Nasal Code to Generate Display Matrix Text =&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;. Including this fiel into your projects should be sufficient to allow you to use a display matrix.&lt;br /&gt;
&lt;br /&gt;
== ScreenText ==&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields of the [[CDU]]. Several elements can be concatenated in a single line by stacking them in a vector, allowing for a more complex formatting of the text. Here is a brake-down of the Nasal class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ScreenText = {&lt;br /&gt;
    # the actual styles name-to-value hash-map&lt;br /&gt;
    # skipped, see above for details&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Static/Public&amp;quot;	&lt;br /&gt;
    func 	new(t,s=32,ptp=nil),&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	sprint(),&lt;br /&gt;
    func 	print(),&lt;br /&gt;
    func 	update(),&lt;br /&gt;
    &lt;br /&gt;
    (ScreenText) blank,    &lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    scalar 	me.style,&lt;br /&gt;
    scalar 	me.text,&lt;br /&gt;
    scalar 	me.property,&lt;br /&gt;
    scalar 	me.size,&lt;br /&gt;
    func 	me.mod_property(property_value),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Note:''' The &amp;lt;tt&amp;gt;ScreenText.blank&amp;lt;/tt&amp;gt; does not create a recursion as it is added after the basic hash has been established -- at least this is what I believe... [[User:Hcc23|Hcc23]] 16:23, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.new&amp;lt;/tt&amp;gt; - The Constructor === &lt;br /&gt;
The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two main elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text (which is 32, what it defaults to if no other value is given); or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background. &lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the actual (multi-char) text of the element. Some limited constructor overloading can be used in order to generate different effects.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  #&lt;br /&gt;
  # 1st method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_text_verbose = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  var test_text_shorter = ScreenText.new(&amp;quot;Hello World!&amp;quot;,34); # does the same as the above as ScreenText[&amp;quot;WHITE&amp;quot;]==34&lt;br /&gt;
This would create screen text element containing the string &amp;lt;tt&amp;gt;Hello World!&amp;lt;/tt&amp;gt; and format it to be large white font. &lt;br /&gt;
&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  #&lt;br /&gt;
  # 2nd method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_prop_verbose = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  var test_prop_shorter = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],34); # result is identical to above  &lt;br /&gt;
This last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;/tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  var test_text_ = ScreenText.new(sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;)),ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
however, the benefit of the 2nd call method is that the ScreenText internally generates a record of the property (stored in &amp;lt;tt&amp;gt;me.property&amp;lt;/tt&amp;gt;) and as such allows to tie a listener to the screen text, such updating the screen text when the property changes. An example for this can be found in the [[Nasal CDU Framework]].&lt;br /&gt;
&lt;br /&gt;
The third way of instantiating a ScreenText allows a modification of the property via a function:&lt;br /&gt;
  #&lt;br /&gt;
  # 3rd method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_modprop_anonymous = ScreenText.new([&amp;quot;This runway is %f football fields long.&amp;quot;,&amp;quot;/some/where/runway-length-yards&amp;quot;,func(prop){return 0.01*prop;}],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  &lt;br /&gt;
  var divide_by_100 = func(value) { return 0.01*value;};&lt;br /&gt;
  var test_modprop_named = ScreenText.new([&amp;quot;This runway is %f football fields long.&amp;quot;,&amp;quot;/some/where/runway-length-yards&amp;quot;,divide_by_100],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
&lt;br /&gt;
What this does is comparable to this:&lt;br /&gt;
  ScreenText.new(sprintf(&amp;quot;This runway is %f football fields long.&amp;quot;,divide_by_100(getprop(&amp;quot;/some/where/runway-length-yards&amp;quot;))),ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
Again, but with the benefit of registering the function as well as the property and output format in the respective ''private'' variables &amp;lt;tt&amp;gt;me.mod_property&amp;lt;/tt&amp;gt;,&amp;lt;tt&amp;gt;me.property&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;me.format&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Example for a changing the style:'''&lt;br /&gt;
&lt;br /&gt;
A slight cheat (but a useful one) is incorporated when it comes to altering the style of a ScreenText element. One example for that would be toggle fields in the CDU in where the text essentially stays the same, but it's color (i.e. style) changes depending on a property. The third method of a constructor call can be used to achieve this, here exemplified by one of the before mentioned CDU toggle fields:&lt;br /&gt;
  var toggle_OnOff_on = func(decision_string) {&lt;br /&gt;
    if (decision_string==&amp;quot;ON&amp;quot;) {&lt;br /&gt;
      # &amp;quot;me&amp;quot; is the screen text object that calls this function...&lt;br /&gt;
      me.style = ScreenText[&amp;quot;GREEN&amp;quot;];&lt;br /&gt;
    } else {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;white&amp;quot;];&lt;br /&gt;
    };&lt;br /&gt;
    return &amp;quot;ON&amp;quot;;&lt;br /&gt;
  };&lt;br /&gt;
  &lt;br /&gt;
  var toggle_OnOff_off = func(decision_string) {&lt;br /&gt;
    if (decision_string==&amp;quot;OFF&amp;quot;) {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;GREEN&amp;quot;];&lt;br /&gt;
    } else {&lt;br /&gt;
      me.style = ScreenText[&amp;quot;white&amp;quot;];&lt;br /&gt;
    }; &lt;br /&gt;
   return &amp;quot;OFF&amp;quot;;&lt;br /&gt;
  };&lt;br /&gt;
  &lt;br /&gt;
  var field_efisCtl = Field.new(ScreenText.new(&amp;quot;EFIS CTL&amp;quot;,ScreenText[&amp;quot;white&amp;quot;]),[&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_off]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;lt;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_on]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
  ],toggle_efisCtl);&lt;br /&gt;
&lt;br /&gt;
The important part here is the generation of the involved ScreenTexts. Note how the first and third ScreenText make use of the third form of calling the ScreenText constructor. However, when you check the property modification functions &amp;lt;tt&amp;gt;toggle_OnOff_on&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;toggle_OnOff_off&amp;lt;/tt&amp;gt;, you will find that they always return the same string (&amp;quot;ON&amp;quot; or &amp;quot;OFF&amp;quot;,resp.) which then is rendered in the &amp;lt;tt&amp;gt;sprintf()&amp;lt;/tt&amp;gt; fashion. However, making use of the &amp;lt;tt&amp;gt;me&amp;lt;/tt&amp;gt; Nasal element, both of these functions alter the style via &amp;lt;tt&amp;gt;me.style&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= Internal Representation of the Data =&lt;br /&gt;
&lt;br /&gt;
As the screen has a fixed resolution (governed by the &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; variables), internally the (0-indexed) screen is held in the FlightGear property tree. For the [[CDU]] the (0,0) cell is stored like this&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable holding the single character that should be displayed, i.e. representing the first layer of the display matrix. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal scalar-type variable (registering as a double in the property tree although it only requires integers), representing the formatting information, i.e. the second layer of the display matrix.&lt;br /&gt;
&lt;br /&gt;
The initial part of that property tree path, i.e. &amp;lt;tt&amp;gt;/instrumentation/cdu&amp;lt;/tt&amp;gt; is actually held in a variable named &amp;lt;tt&amp;gt;PROP&amp;lt;/tt&amp;gt; (which in case of the [[CDU]] is set to the before mentioned value), whereas the display matrix framework adds the &amp;lt;tt&amp;gt;./display/...&amp;lt;/tt&amp;gt; subtree.&lt;br /&gt;
This should allow for an easy inclusion of the framework into other instruments as long as that instrument is properly scoped, i.e. it provides its own (locally scoped) &amp;lt;tt&amp;gt;var PROP = &amp;quot;/where/ever&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Style Encoding ==&lt;br /&gt;
The style of the char to be displayed is encoded via a binary-style key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt; 17&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name that is aimed at capturing the features of that style,for example, &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt;. Each name is then mapped to a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
# The first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;).&lt;br /&gt;
# The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background. So &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; would be the name for a small font size, white font color, non-shaded formatting, whereas &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt; would be standing for a large font size, cyan font color, shaded background formatting.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet correctly implemented but the framework provides an internal hack to make use of some of the formatting information. [[User:Hcc23|Hcc23]] 09:50, 10 May 2011 (EDT) &lt;br /&gt;
&lt;br /&gt;
== The XML Style Interface ==&lt;br /&gt;
In order to make use of the Nasal-maintained data, the 3D model representing the screen has to access the data in the property tree and render it according to the style set there.&lt;br /&gt;
&lt;br /&gt;
This is accomplished via two pieces of code:&lt;br /&gt;
# the fairly generic &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt;&lt;br /&gt;
# a fairly specific and elaborate section in the model specific XML (in case of the [[CDU]] that would be &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== The XML Template for Display Matrix Text ===&lt;br /&gt;
The &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt; essentially provides a template for the creation of an OSGText element, just as other text that is rendered in the the 3D cockpit. The file is comprised of a few sub-sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  &amp;lt;PropertyList&amp;gt;&lt;br /&gt;
    &amp;lt;params&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/params&amp;gt;&lt;br /&gt;
    &amp;lt;text&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/text&amp;gt;&lt;br /&gt;
    &amp;lt;animation&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/animation&amp;gt;&lt;br /&gt;
  &amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; section provides a place for all the elements that need to be altered/adapted for the individual characters, i.e. whenever the template is actually used, the values in this section (and if possible this section only) should be changed. More on that later...&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;text&amp;gt;...&amp;lt;/text&amp;gt;&amp;lt;/tt&amp;gt; section provides the actual ''model'' for the OSGText. It is a fairly complete set of settings from &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;animation&amp;gt;...&amp;lt;/animation&amp;gt;&amp;lt;/tt&amp;gt; section then alters the rendering of the text, particularly it provides for a ''material'', i.e. the color. This section ''should'' hence do the translation from the different styles into the corresponding difference in the rendering. (Which, AFAIK, should be possible through different materials [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)).&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I mentioned earlier that I needed to build in a cheat. Well, it is in the animations section. For some reason I couldn't wrap my head around how to change the color of an animation based upon a variable in the Nasal scope, i.e. a condition like &amp;lt;tt&amp;gt;IF A=1 DO...&amp;lt;/tt&amp;gt;. So I made the display matrix framework put in some extra variables which I did manage to poll, using several animations which get enabled based on mutually exclusive conditions. One drawback (other than it seriously looking lousy) is that I couldn't manage to use that cheat to change the font size. I assume that this is due to the fact that the size is set outside the animation and directly in the text block... So ANY hint on how to generate the text in different sizes (using XML) would be greatly appreciated. [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== The XML ''Instantiation'' of Display Matrix Text ===&lt;br /&gt;
&lt;br /&gt;
So the real work happens to happen inside the CDU's 3D model XML, &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;. In that file, each an every (r,c) cell of the display matrix gets to be a separate model (yes, that means ton's of XML code...). Here is how one such instance looks like:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  			&amp;lt;style&amp;gt;/instrumentation/cdu/display/row-0/col-0/style&amp;lt;/style&amp;gt;&lt;br /&gt;
  			&amp;lt;font-color&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-color&amp;lt;/font-color&amp;gt;&lt;br /&gt;
  			&amp;lt;font-size-m&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-size-m&amp;lt;/font-size-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What happens here is also two-fold:&lt;br /&gt;
# First, the relevant sections in the &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; block get overwritten. &lt;br /&gt;
# Second, the model get's (re-)located at/to the correct position.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Here again traces of my cheat are visible. In theory one wouldn't need the &amp;lt;tt&amp;gt;font-color&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;font-size&amp;lt;/tt&amp;gt; variables, as this information is already encoded in the &amp;lt;tt&amp;gt;style&amp;lt;/tt&amp;gt; variable. However, I couldn't get that to work... [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
As this XML is extremely repetitive, a MATLAB script was used to ''autocode'' this section. (The script below will output a file, &amp;lt;tt&amp;gt;FILENAME&amp;lt;/tt&amp;gt;, containing all the XML which then could be copy-pasted into the model's XML.):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
          &lt;br /&gt;
          charPath  = sprintf('/instrumentation/cdu/display/row-%d/col-%d',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;style&amp;gt;%s&amp;lt;/style&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-color&amp;gt;%s&amp;lt;/font-color&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-size-m&amp;gt;%s&amp;lt;/font-size-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          [charPath '/char'],...&lt;br /&gt;
          [charPath '/style'],...&lt;br /&gt;
          [charPath '/font-color'],...&lt;br /&gt;
          [charPath '/font-size-m'],...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31583</id>
		<title>Nasal Display Matrix Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31583"/>
		<updated>2011-05-10T20:09:27Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Nasal Code to Generate Display Matrix Text */  added overloadd constructors.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
For the development of a Nasal-based [[CDU]] a main hurdle was the replication of the ''screen'' of the [[CDU]]. This Nasal code framework was created to achieve this. Hence, a lot of usage examples can be found in the sources related to the [[CDU]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Type of Replicated Display =&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The CDU utilizes a display matrix. Shown is an early version of page where the text bounding boxes have been enabled for the purpose of better showing the matrix style layout.]]&lt;br /&gt;
&lt;br /&gt;
This framework can replicate any display that uses a fixed row-and-column type screen layout, i.e. a display that has a fixed number of rows (e.g., &amp;lt;tt&amp;gt;var ROWS = 14;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;) and a fixed number of columns (e.g., &amp;lt;tt&amp;gt;var COLS = 24;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;), where each of these &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; cells holds exactly one character, resulting in a fixed-spaced font (like most console type fonts).&lt;br /&gt;
&lt;br /&gt;
Furthermore, each cell also holds the formatting information of that cell, i.e. the information on font, color, size, etc.&lt;br /&gt;
&lt;br /&gt;
Overall, such a display can be thought of as a &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt;x2 matrix (hence the name of the framework) where the first layer (i.e. all (r,c,1) elements) holds the character information for the cell (r,c) and the the second layer (i.e. all (r,c,2) elements) holds the formatting information.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Although generic, the rest of this wiki page will heavily use examples from the [[CDU]] - but the concept of the display matrix can be used for other screen like instruments as well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Nasal Code to Generate Display Matrix Text =&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;. Including this fiel into your projects should be sufficient to allow you to use a display matrix.&lt;br /&gt;
&lt;br /&gt;
== ScreenText ==&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For example, &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields of the [[CDU]]. Several elements can be concatenated in a single line by stacking them in a vector, allowing for a more complex formatting of the text. Here is a brake-down of the Nasal class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ScreenText = {&lt;br /&gt;
    # the actual styles name-to-value hash-map&lt;br /&gt;
    # skipped, see above for details&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Static/Public&amp;quot;	&lt;br /&gt;
    func 	new(t,s=32,ptp=nil),&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	sprint(),&lt;br /&gt;
    func 	print(),&lt;br /&gt;
    func 	update(),&lt;br /&gt;
&lt;br /&gt;
  &lt;br /&gt;
    (ScreenText) blank,    &lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    scalar 	me.style,&lt;br /&gt;
    scalar 	me.text,&lt;br /&gt;
    scalar 	me.property,&lt;br /&gt;
    scalar 	me.size,&lt;br /&gt;
    func 	me.mod_property(property_value),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;tt&amp;gt;.new&amp;lt;/tt&amp;gt; - The Constructor === &lt;br /&gt;
The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two main elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text (which is 32, what it defaults to if no other value is given); or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background. &lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the actual (multi-char) text of the element. Some limited constructor overloading can be used in order to generate different effects.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  #&lt;br /&gt;
  # 1st method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_text_verbose = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  var test_text_shorter = ScreenText.new(&amp;quot;Hello World!&amp;quot;,34); # does the same as the above as ScreenText[&amp;quot;WHITE&amp;quot;]==34&lt;br /&gt;
This would create screen text element containing the string &amp;lt;tt&amp;gt;Hello World!&amp;lt;/tt&amp;gt; and format it to be large white font. &lt;br /&gt;
&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  #&lt;br /&gt;
  # 2nd method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_prop_verbose = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  var test_prop_shorter = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],34); # result is identical to above  &lt;br /&gt;
This last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;/tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  var test_text_ = ScreenText.new(sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;)),ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
however, the benefit of the 2nd call method is that the ScreenText internally generates a record of the property (stored in &amp;lt;tt&amp;gt;me.property&amp;lt;/tt&amp;gt;) and as such allows to tie a listener to the screen text, such updating the screen text when the property changes. An example for this can be found in the [[Nasal CDU Framework]].&lt;br /&gt;
&lt;br /&gt;
The third way of instantiating a ScreenText allows a modification of the property via a function:&lt;br /&gt;
  #&lt;br /&gt;
  # 3rd method to instantiate a ScreenText&lt;br /&gt;
  #&lt;br /&gt;
  var test_modprop_anonymous = ScreenText.new([&amp;quot;This runway is %f football fields long.&amp;quot;,&amp;quot;/some/where/runway-length-yards&amp;quot;,func(prop){return 0.01*prop;}],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
  &lt;br /&gt;
  var divide_by_100 = func(value) { return 0.01*value;};&lt;br /&gt;
  var test_modprop_named = ScreenText.new([&amp;quot;This runway is %f football fields long.&amp;quot;,&amp;quot;/some/where/runway-length-yards&amp;quot;,divide_by_100],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
&lt;br /&gt;
What this does is comparable to this:&lt;br /&gt;
  ScreenText.new(sprintf(&amp;quot;This runway is %f football fields long.&amp;quot;,divide_by_100(getprop(&amp;quot;/some/where/runway-length-yards&amp;quot;))),ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
Again, but with the benefit of registering the function as well as the property and output format in the respective ''private'' variables &amp;lt;tt&amp;gt;me.mod_property&amp;lt;/tt&amp;gt;,&amp;lt;tt&amp;gt;me.property&amp;lt;/tt&amp;gt;, and &amp;lt;tt&amp;gt;me.format&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= Internal Representation of the Data =&lt;br /&gt;
&lt;br /&gt;
As the screen has a fixed resolution (governed by the &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; variables), internally the (0-indexed) screen is held in the FlightGear property tree. For the [[CDU]] the (0,0) cell is stored like this&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable holding the single character that should be displayed, i.e. representing the first layer of the display matrix. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal scalar-type variable (registering as a double in the property tree although it only requires integers), representing the formatting information, i.e. the second layer of the display matrix.&lt;br /&gt;
&lt;br /&gt;
The initial part of that property tree path, i.e. &amp;lt;tt&amp;gt;/instrumentation/cdu&amp;lt;/tt&amp;gt; is actually held in a variable named &amp;lt;tt&amp;gt;PROP&amp;lt;/tt&amp;gt; (which in case of the [[CDU]] is set to the before mentioned value), whereas the display matrix framework adds the &amp;lt;tt&amp;gt;./display/...&amp;lt;/tt&amp;gt; subtree.&lt;br /&gt;
This should allow for an easy inclusion of the framework into other instruments as long as that instrument is properly scoped, i.e. it provides its own (locally scoped) &amp;lt;tt&amp;gt;var PROP = &amp;quot;/where/ever&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Style Encoding ==&lt;br /&gt;
The style of the char to be displayed is encoded via a binary-style key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt; 17&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name that is aimed at capturing the features of that style,for example, &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt;. Each name is then mapped to a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
# The first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;).&lt;br /&gt;
# The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background. So &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; would be the name for a small font size, white font color, non-shaded formatting, whereas &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt; would be standing for a large font size, cyan font color, shaded background formatting.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet correctly implemented but the framework provides an internal hack to make use of some of the formatting information. [[User:Hcc23|Hcc23]] 09:50, 10 May 2011 (EDT) &lt;br /&gt;
&lt;br /&gt;
== The XML Style Interface ==&lt;br /&gt;
In order to make use of the Nasal-maintained data, the 3D model representing the screen has to access the data in the property tree and render it according to the style set there.&lt;br /&gt;
&lt;br /&gt;
This is accomplished via two pieces of code:&lt;br /&gt;
# the fairly generic &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt;&lt;br /&gt;
# a fairly specific and elaborate section in the model specific XML (in case of the [[CDU]] that would be &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== The XML Template for Display Matrix Text ===&lt;br /&gt;
The &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt; essentially provides a template for the creation of an OSGText element, just as other text that is rendered in the the 3D cockpit. The file is comprised of a few sub-sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  &amp;lt;PropertyList&amp;gt;&lt;br /&gt;
    &amp;lt;params&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/params&amp;gt;&lt;br /&gt;
    &amp;lt;text&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/text&amp;gt;&lt;br /&gt;
    &amp;lt;animation&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/animation&amp;gt;&lt;br /&gt;
  &amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; section provides a place for all the elements that need to be altered/adapted for the individual characters, i.e. whenever the template is actually used, the values in this section (and if possible this section only) should be changed. More on that later...&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;text&amp;gt;...&amp;lt;/text&amp;gt;&amp;lt;/tt&amp;gt; section provides the actual ''model'' for the OSGText. It is a fairly complete set of settings from &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;animation&amp;gt;...&amp;lt;/animation&amp;gt;&amp;lt;/tt&amp;gt; section then alters the rendering of the text, particularly it provides for a ''material'', i.e. the color. This section ''should'' hence do the translation from the different styles into the corresponding difference in the rendering. (Which, AFAIK, should be possible through different materials [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)).&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I mentioned earlier that I needed to build in a cheat. Well, it is in the animations section. For some reason I couldn't wrap my head around how to change the color of an animation based upon a variable in the Nasal scope, i.e. a condition like &amp;lt;tt&amp;gt;IF A=1 DO...&amp;lt;/tt&amp;gt;. So I made the display matrix framework put in some extra variables which I did manage to poll, using several animations which get enabled based on mutually exclusive conditions. One drawback (other than it seriously looking lousy) is that I couldn't manage to use that cheat to change the font size. I assume that this is due to the fact that the size is set outside the animation and directly in the text block... So ANY hint on how to generate the text in different sizes (using XML) would be greatly appreciated. [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== The XML ''Instantiation'' of Display Matrix Text ===&lt;br /&gt;
&lt;br /&gt;
So the real work happens to happen inside the CDU's 3D model XML, &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;. In that file, each an every (r,c) cell of the display matrix gets to be a separate model (yes, that means ton's of XML code...). Here is how one such instance looks like:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  			&amp;lt;style&amp;gt;/instrumentation/cdu/display/row-0/col-0/style&amp;lt;/style&amp;gt;&lt;br /&gt;
  			&amp;lt;font-color&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-color&amp;lt;/font-color&amp;gt;&lt;br /&gt;
  			&amp;lt;font-size-m&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-size-m&amp;lt;/font-size-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What happens here is also two-fold:&lt;br /&gt;
# First, the relevant sections in the &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; block get overwritten. &lt;br /&gt;
# Second, the model get's (re-)located at/to the correct position.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Here again traces of my cheat are visible. In theory one wouldn't need the &amp;lt;tt&amp;gt;font-color&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;font-size&amp;lt;/tt&amp;gt; variables, as this information is already encoded in the &amp;lt;tt&amp;gt;style&amp;lt;/tt&amp;gt; variable. However, I couldn't get that to work... [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
As this XML is extremely repetitive, a MATLAB script was used to ''autocode'' this section. (The script below will output a file, &amp;lt;tt&amp;gt;FILENAME&amp;lt;/tt&amp;gt;, containing all the XML which then could be copy-pasted into the model's XML.):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
          &lt;br /&gt;
          charPath  = sprintf('/instrumentation/cdu/display/row-%d/col-%d',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;style&amp;gt;%s&amp;lt;/style&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-color&amp;gt;%s&amp;lt;/font-color&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-size-m&amp;gt;%s&amp;lt;/font-size-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          [charPath '/char'],...&lt;br /&gt;
          [charPath '/style'],...&lt;br /&gt;
          [charPath '/font-color'],...&lt;br /&gt;
          [charPath '/font-size-m'],...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31582</id>
		<title>Nasal Display Matrix Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31582"/>
		<updated>2011-05-10T19:15:41Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: some restructuring and expanding&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
For the development of a Nasal-based [[CDU]] a main hurdle was the replication of the ''screen'' of the [[CDU]]. This Nasal code framework was created to achieve this. Hence, a lot of usage examples can be found in the sources related to the [[CDU]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Type of Replicated Display =&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The CDU utilizes a display matrix. Shown is an early version of page where the text bounding boxes have been enabled for the purpose of better showing the matrix style layout.]]&lt;br /&gt;
&lt;br /&gt;
This framework can replicate any display that uses a fixed row-and-column type screen layout, i.e. a display that has a fixed number of rows (e.g., &amp;lt;tt&amp;gt;var ROWS = 14;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;) and a fixed number of columns (e.g., &amp;lt;tt&amp;gt;var COLS = 24;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;), where each of these &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; cells holds exactly one character, resulting in a fixed-spaced font (like most console type fonts).&lt;br /&gt;
&lt;br /&gt;
Furthermore, each cell also holds the formatting information of that cell, i.e. the information on font, color, size, etc.&lt;br /&gt;
&lt;br /&gt;
Overall, such a display can be thought of as a &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt;x2 matrix (hence the name of the framework) where the first layer (i.e. all (r,c,1) elements) holds the character information for the cell (r,c) and the the second layer (i.e. all (r,c,2) elements) holds the formatting information.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Although generic, the rest of this wiki page will heavily use examples from the [[CDU]] - but the concept of the display matrix can be used for other screen like instruments as well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Nasal Code to Generate Display Matrix Text =&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;.&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields. Several elements can be concatenated in a single line by stacking them in a vector. The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text; or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background.&lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the text element. Here some limited constructor overloading can be used.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  var test_text = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  var test_prop = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
The last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;/tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;));&lt;br /&gt;
Furthermore, whenever a property is used in a screen text element on a subpage, the suppage, when displayed, registers listeners on all utilized properties, resulting in updated data on the screen. When the sup page is changed, the listeners are de-registered.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Internal Representation of the Data =&lt;br /&gt;
&lt;br /&gt;
As the screen has a fixed resolution (governed by the &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; variables), internally the (0-indexed) screen is held in the FlightGear property tree. For the [[CDU]] the (0,0) cell is stored like this&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable holding the single character that should be displayed, i.e. representing the first layer of the display matrix. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal scalar-type variable (registering as a double in the property tree although it only requires integers), representing the formatting information, i.e. the second layer of the display matrix.&lt;br /&gt;
&lt;br /&gt;
The initial part of that property tree path, i.e. &amp;lt;tt&amp;gt;/instrumentation/cdu&amp;lt;/tt&amp;gt; is actually held in a variable named &amp;lt;tt&amp;gt;PROP&amp;lt;/tt&amp;gt; (which in case of the [[CDU]] is set to the before mentioned value), whereas the display matrix framework adds the &amp;lt;tt&amp;gt;./display/...&amp;lt;/tt&amp;gt; subtree.&lt;br /&gt;
This should allow for an easy inclusion of the framework into other instruments as long as that instrument is properly scoped, i.e. it provides its own (locally scoped) &amp;lt;tt&amp;gt;var PROP = &amp;quot;/where/ever&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Style Encoding ==&lt;br /&gt;
The style of the char to be displayed is encoded via a binary-style key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt; 17&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name that is aimed at capturing the features of that style,for example, &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt;. Each name is then mapped to a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
# The first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;).&lt;br /&gt;
# The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background. So &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; would be the name for a small font size, white font color, non-shaded formatting, whereas &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt; would be standing for a large font size, cyan font color, shaded background formatting.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet correctly implemented but the framework provides an internal hack to make use of some of the formatting information. [[User:Hcc23|Hcc23]] 09:50, 10 May 2011 (EDT) &lt;br /&gt;
&lt;br /&gt;
== The XML Style Interface ==&lt;br /&gt;
In order to make use of the Nasal-maintained data, the 3D model representing the screen has to access the data in the property tree and render it according to the style set there.&lt;br /&gt;
&lt;br /&gt;
This is accomplished via two pieces of code:&lt;br /&gt;
# the fairly generic &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt;&lt;br /&gt;
# a fairly specific and elaborate section in the model specific XML (in case of the [[CDU]] that would be &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
=== The XML Template for Display Matrix Text ===&lt;br /&gt;
The &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt; essentially provides a template for the creation of an OSGText element, just as other text that is rendered in the the 3D cockpit. The file is comprised of a few sub-sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  &amp;lt;PropertyList&amp;gt;&lt;br /&gt;
    &amp;lt;params&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/params&amp;gt;&lt;br /&gt;
    &amp;lt;text&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/text&amp;gt;&lt;br /&gt;
    &amp;lt;animation&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/animation&amp;gt;&lt;br /&gt;
  &amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; section provides a place for all the elements that need to be altered/adapted for the individual characters, i.e. whenever the template is actually used, the values in this section (and if possible this section only) should be changed. More on that later...&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;text&amp;gt;...&amp;lt;/text&amp;gt;&amp;lt;/tt&amp;gt; section provides the actual ''model'' for the OSGText. It is a fairly complete set of settings from &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;&amp;lt;animation&amp;gt;...&amp;lt;/animation&amp;gt;&amp;lt;/tt&amp;gt; section then alters the rendering of the text, particularly it provides for a ''material'', i.e. the color. This section ''should'' hence do the translation from the different styles into the corresponding difference in the rendering. (Which, AFAIK, should be possible through different materials [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)).&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I mentioned earlier that I needed to build in a cheat. Well, it is in the animations section. For some reason I couldn't wrap my head around how to change the color of an animation based upon a variable in the Nasal scope, i.e. a condition like &amp;lt;tt&amp;gt;IF A=1 DO...&amp;lt;/tt&amp;gt;. So I made the display matrix framework put in some extra variables which I did manage to poll, using several animations which get enabled based on mutually exclusive conditions. One drawback (other than it seriously looking lousy) is that I couldn't manage to use that cheat to change the font size. I assume that this is due to the fact that the size is set outside the animation and directly in the text block... So ANY hint on how to generate the text in different sizes (using XML) would be greatly appreciated. [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== The XML ''Instantiation'' of Display Matrix Text ===&lt;br /&gt;
&lt;br /&gt;
So the real work happens to happen inside the CDU's 3D model XML, &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;. In that file, each an every (r,c) cell of the display matrix gets to be a separate model (yes, that means ton's of XML code...). Here is how one such instance looks like:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  			&amp;lt;style&amp;gt;/instrumentation/cdu/display/row-0/col-0/style&amp;lt;/style&amp;gt;&lt;br /&gt;
  			&amp;lt;font-color&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-color&amp;lt;/font-color&amp;gt;&lt;br /&gt;
  			&amp;lt;font-size-m&amp;gt;/instrumentation/cdu/display/row-0/col-0/font-size-m&amp;lt;/font-size-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What happens here is also two-fold:&lt;br /&gt;
# First, the relevant sections in the &amp;lt;tt&amp;gt;&amp;lt;params&amp;gt;...&amp;lt;/params&amp;gt;&amp;lt;/tt&amp;gt; block get overwritten. &lt;br /&gt;
# Second, the model get's (re-)located at/to the correct position.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Here again traces of my cheat are visible. In theory one wouldn't need the &amp;lt;tt&amp;gt;font-color&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;font-size&amp;lt;/tt&amp;gt; variables, as this information is already encoded in the &amp;lt;tt&amp;gt;style&amp;lt;/tt&amp;gt; variable. However, I couldn't get that to work... [[User:Hcc23|Hcc23]] 15:15, 10 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
As this XML is extremely repetitive, a MATLAB script was used to ''autocode'' this section. (The script below will output a file, &amp;lt;tt&amp;gt;FILENAME&amp;lt;/tt&amp;gt;, containing all the XML which then could be copy-pasted into the model's XML.):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
          &lt;br /&gt;
          charPath  = sprintf('/instrumentation/cdu/display/row-%d/col-%d',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;style&amp;gt;%s&amp;lt;/style&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-color&amp;gt;%s&amp;lt;/font-color&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;font-size-m&amp;gt;%s&amp;lt;/font-size-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          [charPath '/char'],...&lt;br /&gt;
          [charPath '/style'],...&lt;br /&gt;
          [charPath '/font-color'],...&lt;br /&gt;
          [charPath '/font-size-m'],...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31578</id>
		<title>Nasal Display Matrix Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31578"/>
		<updated>2011-05-10T14:59:17Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
For the development of a Nasal-based [[CDU]] a main hurdle was the replication of the ''screen'' of the [[CDU]]. This Nasal code framework was created to achieve this. Hence, a lot of usage examples can be found in the sources related to the [[CDU]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Type of Replicated Display =&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The CDU utilizes a display matrix. Shown is an early version of page where the text bounding boxes have been enabled for the purpose of better showing the matrix style layout.]]&lt;br /&gt;
&lt;br /&gt;
This framework can replicate any display that uses a fixed row-and-column type screen layout, i.e. a display that has a fixed number of rows (e.g., &amp;lt;tt&amp;gt;var ROWS = 14;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;) and a fixed number of columns (e.g., &amp;lt;tt&amp;gt;var COLS = 24;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;), where each of these &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; cells holds exactly one character, resulting in a fixed-spaced font (like most console type fonts).&lt;br /&gt;
&lt;br /&gt;
Furthermore, each cell also holds the formatting information of that cell, i.e. the information on font, color, size, etc.&lt;br /&gt;
&lt;br /&gt;
Overall, such a display can be thought of as a &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt;x2 matrix (hence the name of the framework) where the first layer (i.e. all (r,c,1) elements) holds the character information for the cell (r,c) and the the second layer (i.e. all (r,c,2) elements) holds the formatting information.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Although generic, the rest of this wiki page will heavily use examples from the [[CDU]] - but the concept of the display matrix can be used for other screen like instruments as well.&lt;br /&gt;
&lt;br /&gt;
= Internal Representation of the Data=&lt;br /&gt;
&lt;br /&gt;
As the screen has a fixed resolution (governed by the &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; variables), internally the (0-indexed) screen is held in the FlightGear property tree. For the [[CDU]] the (0,0) cell is stored like this&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable holding the single character that should be displayed, i.e. representing the first layer of the display matrix. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal scalar-type variable (registering as a double in the property tree although it only requires integers), representing the formatting information, i.e. the second layer of the display matrix.&lt;br /&gt;
&lt;br /&gt;
The initial part of that property tree path, i.e. &amp;lt;tt&amp;gt;/instrumentation/cdu&amp;lt;/tt&amp;gt; is actually held in a variable named &amp;lt;tt&amp;gt;PROP&amp;lt;/tt&amp;gt; (which in case of the [[CDU]] is set to the before mentioned value), whereas the display matrix framework adds the &amp;lt;tt&amp;gt;./display/...&amp;lt;/tt&amp;gt; subtree.&lt;br /&gt;
This should allow for an easy inclusion of the framework into other instruments as long as that instrument is properly scoped, i.e. it provides its own (locally scoped) &amp;lt;tt&amp;gt;var PROP = &amp;quot;/where/ever&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Style Encoding ==&lt;br /&gt;
The style of the char to be displayed is encoded via a binary-style key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt; 17&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name that is aimed at capturing the features of that style,for example, &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt;. Each name is then mapped to a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
# The first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;).&lt;br /&gt;
# The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background. So &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; would be the name for a small font size, white font color, non-shaded formatting, whereas &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt; would be standing for a large font size, cyan font color, shaded background formatting.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet correctly implemented but the framework provides an internal hack to make use of some of the formatting information. [[User:Hcc23|Hcc23]] 09:50, 10 May 2011 (EDT) &lt;br /&gt;
&lt;br /&gt;
== The XML Style Interface ==&lt;br /&gt;
In order to make use of the Nasal-maintained data, the 3D model representing the screen has to access the data in the property tree and render it according to the style set there.&lt;br /&gt;
&lt;br /&gt;
This is accomplished via two pieces of code:&lt;br /&gt;
# the fairly generic &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt;&lt;br /&gt;
# a fairly specific and elaborate section in the model specific XML (in case of the [[CDU]] that would be &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
The &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt; essentially provides a template for the creation of an OSGText element, just as other text that is rendered in the the 3D cockpit. The file is comprised of a few sub-sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  &amp;lt;PropertyList&amp;gt;&lt;br /&gt;
    &amp;lt;params&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/params&amp;gt;&lt;br /&gt;
    &amp;lt;text&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/text&amp;gt;&lt;br /&gt;
    &amp;lt;animation&amp;gt;&lt;br /&gt;
      ...&lt;br /&gt;
    &amp;lt;/animation&amp;gt;&lt;br /&gt;
  &amp;lt;/PropertyList&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Nasal Code =&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;.&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields. Several elements can be concattenated in a single line by stacking them in a vector. The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text; or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background.&lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the text element. Here some limited constructor overloading can be used.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  var test_text = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  var test_prop = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
The last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;));&lt;br /&gt;
Furthermore, whenever a property is used in a screen text element on a subpage, the suppage, when displayed, registers listeners on all utilized properties, resulting in updated data on the screen. When the sup page is changed, the listeners are de-registered.&lt;br /&gt;
&lt;br /&gt;
= XML Code =&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== Generating the offset code ==&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31577</id>
		<title>Nasal Display Matrix Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31577"/>
		<updated>2011-05-10T14:31:38Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: started on the nasal-xml interplay...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
For the development of a Nasal-based [[CDU]] a main hurdle was the replication of the ''screen'' of the [[CDU]]. This Nasal code framework was created to achieve this. Hence, a lot of usage examples can be found in the sources related to the [[CDU]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Type of Replicated Display =&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The CDU utilizes a display matrix. Shown is an early version of page where the text bounding boxes have been enabled for the purpose of better showing the matrix style layout.]]&lt;br /&gt;
&lt;br /&gt;
This framework can replicate any display that uses a fixed row-and-column type screen layout, i.e. a display that has a fixed number of rows (e.g., &amp;lt;tt&amp;gt;var ROWS = 14;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;) and a fixed number of columns (e.g., &amp;lt;tt&amp;gt;var COLS = 24;&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;), where each of these &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; cells holds exactly one character, resulting in a fixed-spaced font (like most console type fonts).&lt;br /&gt;
&lt;br /&gt;
Furthermore, each cell also holds the formatting information of that cell, i.e. the information on font, color, size, etc.&lt;br /&gt;
&lt;br /&gt;
Overall, such a display can be thought of as a &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt;x2 matrix (hence the name of the framework) where the first layer (i.e. all (r,c,1) elements) holds the character information for the cell (r,c) and the the second layer (i.e. all (r,c,2) elements) holds the formatting information.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Although generic, the rest of this wiki page will heavily use examples from the [[CDU]] - but the concept of the display matrix can be used for other screen like instruments as well.&lt;br /&gt;
&lt;br /&gt;
= Internal Representation of the Data=&lt;br /&gt;
&lt;br /&gt;
As the screen has a fixed resolution (governed by the &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; variables), internally the (0-indexed) screen is held in the FlightGear property tree. For the [[CDU]] the (0,0) cell is stored like this&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable holding the single character that should be displayed, i.e. representing the first layer of the display matrix. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal scalar-type variable (registering as a double in the property tree although it only requires integers), representing the formatting information, i.e. the second layer of the display matrix.&lt;br /&gt;
&lt;br /&gt;
The initial part of that property tree path, i.e. &amp;lt;tt&amp;gt;/instrumentation/cdu&amp;lt;/tt&amp;gt; is actually held in a variable named &amp;lt;tt&amp;gt;PROP&amp;lt;/tt&amp;gt; (which in case of the [[CDU]] is set to the before mentioned value), whereas the display matrix framework adds the &amp;lt;tt&amp;gt;./display/...&amp;lt;/tt&amp;gt; subtree.&lt;br /&gt;
This should allow for an easy inclusion of the framework into other instruments as long as that instrument is properly scoped, i.e. it provides its own (locally scoped) &amp;lt;tt&amp;gt;var PROP = &amp;quot;/where/ever&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Style Encoding ==&lt;br /&gt;
The style of the char to be displayed is encoded via a binary-style key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt; 17&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name that is aimed at capturing the features of that style,for example, &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt;. Each name is then mapped to a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
# The first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;).&lt;br /&gt;
# The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background. So &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; would be the name for a small font size, white font color, non-shaded formatting, whereas &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt; would be standing for a large font size, cyan font color, shaded background formatting.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet correctly implemented but the framework provides an internal hack to make use of some of the formatting information. [[User:Hcc23|Hcc23]] 09:50, 10 May 2011 (EDT) &lt;br /&gt;
&lt;br /&gt;
== The XML Style Interface ==&lt;br /&gt;
In order to make use of the Nasal-maintained data, the 3D model representing the screen has to access the data in the property tree and render it according to the style set there.&lt;br /&gt;
&lt;br /&gt;
This is accomplished via two pieces of code:&lt;br /&gt;
# the fairly generic &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt;&lt;br /&gt;
# a fairly specific and elaborate section in the model specific XML (in case of the [[CDU]] that would be &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Nasal Code =&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;.&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields. Several elements can be concattenated in a single line by stacking them in a vector. The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text; or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background.&lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the text element. Here some limited constructor overloading can be used.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  var test_text = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  var test_prop = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
The last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;));&lt;br /&gt;
Furthermore, whenever a property is used in a screen text element on a subpage, the suppage, when displayed, registers listeners on all utilized properties, resulting in updated data on the screen. When the sup page is changed, the listeners are de-registered.&lt;br /&gt;
&lt;br /&gt;
= XML Code =&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== Generating the offset code ==&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31576</id>
		<title>Nasal Display Matrix Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31576"/>
		<updated>2011-05-10T13:50:57Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: worked on the style section&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
For the development of a Nasal-based [[CDU]] a main hurdle was the replication of the ''screen'' of the [[CDU]]. This Nasal code framework was achieve this. Hence, a lot of usage examples can be found in the sources related to the [[CDU]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Type of Replicated Display =&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The CDU utilizes a display matrix. Shown is an early version of page where the text bounding boxes have been enabled for the purpose of better showing the matrix style layout.]]&lt;br /&gt;
&lt;br /&gt;
This framework can replicate any display that uses a fixed row-and-column type screen layout, i.e. a display that has a fixed number of rows (e.g., &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;) and a fixed number of columns (e.g., &amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;), where each of these &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; cells holds exactly one character, resulting in a fixed-spaced font (like most console type fonts).&lt;br /&gt;
&lt;br /&gt;
Furthermore, each cell also holds the formatting information of that cell, i.e. the information on font, color, size, etc.&lt;br /&gt;
&lt;br /&gt;
Overall, such a display can be thought of as a &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt;x2 matrix (hence the name of the framework) where the first layer (i.e. all (r,c,1) elements) holds the character information for the cell (r,c) and the the second layer (i.e. all (r,c,2) elements) holds the formatting information.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Although generic, the rest of this wiki page will heavily use examples from the [[CDU]] - but the concept of the display matrix can be used for other screen like instruments as well.&lt;br /&gt;
&lt;br /&gt;
= Internal Representation of the Data=&lt;br /&gt;
&lt;br /&gt;
As the screen has a fixed resolution (governed by the &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; variables), internally the (0-indexed) screen is held in the FlightGear property tree. For the [[CDU]] the (0,0) cell is stored like this&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable holding the single character that should be displayed, i.e. representing the first layer of the display matrix. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal scalar-type variable (registering as a double in the property tree although it only requires integers), representing the formatting information, i.e. the second layer of the display matrix.&lt;br /&gt;
&lt;br /&gt;
The initial part of that property tree path, i.e. &amp;lt;tt&amp;gt;/instrumentation/cdu&amp;lt;/tt&amp;gt; is actually held in a variable named &amp;lt;tt&amp;gt;PROP&amp;lt;/tt&amp;gt; (which in case of the [[CDU]] is set to the before mentioned value), whereas the display matrix framework adds the &amp;lt;tt&amp;gt;./display/...&amp;lt;/tt&amp;gt; subtree.&lt;br /&gt;
This should allow for an easy inclusion of the framework into other instruments as long as that instrument is properly scoped, i.e. it provides its own (locally scoped) &amp;lt;tt&amp;gt;var PROP = &amp;quot;/where/ever&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Style Encoding ==&lt;br /&gt;
The style of the char to be displayed is encoded via a binary-style key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt; 17&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name that is aimed at capturing the features of that style,for example, &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; or &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt;. Each name is then mapped to a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
# The first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;).&lt;br /&gt;
# The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background. So &amp;lt;tt&amp;gt;&amp;quot;white&amp;quot;&amp;lt;/tt&amp;gt; would be the name for a small font size, white font color, non-shaded formatting, whereas &amp;lt;tt&amp;gt;&amp;quot;CYAN_&amp;quot;&amp;lt;/tt&amp;gt; would be standing for a large font size, cyan font color, shaded background formatting.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet correctly implemented but the framework provides an internal hack to make use of some of the formatting information. [[User:Hcc23|Hcc23]] 09:50, 10 May 2011 (EDT) &lt;br /&gt;
&lt;br /&gt;
= Nasal Code =&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;.&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields. Several elements can be concattenated in a single line by stacking them in a vector. The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text; or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background.&lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the text element. Here some limited constructor overloading can be used.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  var test_text = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  var test_prop = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
The last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;));&lt;br /&gt;
Furthermore, whenever a property is used in a screen text element on a subpage, the suppage, when displayed, registers listeners on all utilized properties, resulting in updated data on the screen. When the sup page is changed, the listeners are de-registered.&lt;br /&gt;
&lt;br /&gt;
= XML Code =&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== Generating the offset code ==&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31575</id>
		<title>Nasal Display Matrix Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31575"/>
		<updated>2011-05-10T13:20:28Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: Changed introduction&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
For the development of a Nasal-based [[CDU]] a main hurdle was the replication of the ''screen'' of the [[CDU]]. This Nasal code framework was achieve this. Hence, a lot of usage examples can be found in the sources related to the [[CDU]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Type of Replicated Display =&lt;br /&gt;
&lt;br /&gt;
This framework can replicate any display that uses a fixed row-and-column type screen layout, i.e. a display that has a fixed number of rows (e.g., &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;) and a fixed number of columns (e.g., &amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;), where each of these &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt; cells holds exactly one character, resulting in a fixed-spaced font (like most console type fonts).&lt;br /&gt;
&lt;br /&gt;
Furthermore, each cell also holds the formatting information of that cell, i.e. the information on font, color, size, etc.&lt;br /&gt;
&lt;br /&gt;
Overall, such a display can be thought of as a &amp;lt;tt&amp;gt;ROWS&amp;lt;/tt&amp;gt;x&amp;lt;tt&amp;gt;COLS&amp;lt;/tt&amp;gt;x2 matrix (hence the name of the framework) where the first layer (i.e. all (r,c,1) elements) holds the character information for the cell (r,c) and the the second layer (i.e. all (r,c,2) elements) holds the formatting information.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Internal Representation =&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The utilizes display matrix, showing the text bounding boxes for clarity.]]&lt;br /&gt;
As the screen has a &amp;quot;fixed&amp;quot; resolution, internally the screen is represented as a 14-by-24(-by-2) matrix. The zero-indexed matrix is held in the property tree:&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal double-type variable (although it is only integers).&lt;br /&gt;
&lt;br /&gt;
The style of the char is encoded via a binary key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt;  7&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name (used in the Nasal code for the CDU), which is resolved into a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
the first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;). The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet implemented. [[User:Hcc23|Hcc23]] 14:01, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Nasal Code =&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;.&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields. Several elements can be concattenated in a single line by stacking them in a vector. The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text; or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background.&lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the text element. Here some limited constructor overloading can be used.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  var test_text = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  var test_prop = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
The last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;));&lt;br /&gt;
Furthermore, whenever a property is used in a screen text element on a subpage, the suppage, when displayed, registers listeners on all utilized properties, resulting in updated data on the screen. When the sup page is changed, the listeners are de-registered.&lt;br /&gt;
&lt;br /&gt;
= XML Code =&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== Generating the offset code ==&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31574</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31574"/>
		<updated>2011-05-10T12:59:50Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Additional Infrastructure */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
These are the core classes in the CDU framework. The documentation should show a brief comment on what each variable or function is intended to do, particularly the ones that are important for the '''creation''' of an actual, content-filled CDU page.&lt;br /&gt;
&lt;br /&gt;
Although Nasal as such has no support for this, the internal stuff in a class is sectioned in three categories, borrowing language from &amp;lt;tt&amp;gt;C++&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Static:''' Stuff in this section is mainly identified by being made directly as part of the &amp;lt;tt&amp;gt;hash&amp;lt;/tt&amp;gt; (as opposed to being ''tagged on'' by the the &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; constructor. Elements in here also follow a ''camelCase'' type of notation, whereas ''members'' use an ''underscore_naming_convetion''. Please note that although meant to be comparable to statics, in hindsight a lot of them would be better placed in the member section Public...&lt;br /&gt;
&lt;br /&gt;
* '''Public:''' Elements in here are created from inside the &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; constructor and follow an ''underscore_naming_convetion''. In a perfect world these would only be accessing functions, as exposing variables is always prone for trouble when the time for a redesign comes... Elements in here should be the only ones used in the creation of a page - in a perfect world.&lt;br /&gt;
&lt;br /&gt;
* '''Private:''' Elements in here are created from inside the &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; constructor and follow an ''underscore_naming_convetion''. Although readable by everybody, access to these elements should be limited to functions in the static and public parts of the classes code. Particularly no page creation (user) code should need to access this information.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' I know that I violate these rules. Yes. But I have rewritten the framework to often to (at this point) care much about it - particularly as it seems to be working. Please, feel free to correct the Nasal code I have written (which might involve the pain of revisiting the page creation sections... Sorry for that.) [[User:Hcc23|Hcc23]] 14:45, 9 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	formatOutput(input_data),&lt;br /&gt;
    func 	getScreenTextVector(),&lt;br /&gt;
    func 	new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.used_properties,&lt;br /&gt;
    vector 	me.line_data,&lt;br /&gt;
    scalar 	me.line_string_length,&lt;br /&gt;
    func 	me.enable(),&lt;br /&gt;
    func 	me.disable(),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
A field holds two lines, the label and the data line, as well as information about what the associated line select key does.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Field = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	new(label,data,key_action=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
  &lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.used_properties(),&lt;br /&gt;
    func 	me.lsk_binding(),&lt;br /&gt;
    func 	me.enable_lsk(),&lt;br /&gt;
    func 	me.disable_lsk(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    (Line)	me.label_line,	&lt;br /&gt;
    (Line) 	me.data_line,&lt;br /&gt;
    scalar 	me.lsk_active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
A SubPage is actually the main element in the CDU framework. It holds the content via its fields and manages the updating of the CDU screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var SubPage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    (Field) 	blankField,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	updateField(field, side, lsk_index),	&lt;br /&gt;
    func 	displayFields(field_vector, side),&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	new(parent_base_page,name=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar      me.separator,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    func 	me.register_field(field_pos,field),&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.parent,&lt;br /&gt;
    scalar      me.title,&lt;br /&gt;
    scalar      me.status,&lt;br /&gt;
    vector 	me.left_field,&lt;br /&gt;
    vector      me.right_field,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
A BasePage is exactly that: a base to hold sub pages. A base page most closely represents the concept of a '''page''' in a CDU.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var BasePage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	regiserInPropTree(path)&lt;br /&gt;
    func 	new(name,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.active_sub_page_id,&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    vector 	me.sub_pages,&lt;br /&gt;
    scalar 	me.title,&lt;br /&gt;
    scalar 	me.status,&lt;br /&gt;
    &lt;br /&gt;
  };  &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
The CDU is the main class for the instrument. Each simulated CDU should have one and only one CDU instance associated to it. This is intended to support multiple CDUs showing different content in the future.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var CDU = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    func 	M_ERROR(message_string),&lt;br /&gt;
    func 	M_WARNING(message_string),&lt;br /&gt;
    func 	M_NOTE(message_string),&lt;br /&gt;
    func 	M_HINT(message_string),&lt;br /&gt;
  &lt;br /&gt;
    func 	updateDisplay(),&lt;br /&gt;
    scalar 	activeBasePageID,&lt;br /&gt;
  &lt;br /&gt;
    (ScratchPad) 		scratchPad,&lt;br /&gt;
    (Timer) 			timer,&lt;br /&gt;
    (ListenerCollection) 	listOfListeners,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Additional Infrastructure =&lt;br /&gt;
The previous section was more concerned with the conceptually necessary pieces for a/the core CDU. This section introduces the other elements the framework introduces in order to code a functional CDU.&lt;br /&gt;
&lt;br /&gt;
Besides from the additional pieces presented here, there also is a page on the [[Nasal Display Matrix Framework]] which, although developed for the CDU, might be useful for any kind of fixed row-column based text-type screen in a cockpit. (As this code is conceptually separate from the CDU, its documentation is in a separate wiki page.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ScratchPad ==&lt;br /&gt;
&lt;br /&gt;
The ScratchPad is the input/output line in the CDU(s). The scratch pas as such is kind of different from the rest of the CDU(s) as the scratch pad messages are truly static, i.e. they happen to be displayed on all CDUs in the cockpit, no matter what the individual CDU is otherwise showing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ScratchPad = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	messages,&lt;br /&gt;
    scalar 	deleteString, # &amp;quot;DELETE&amp;quot;~&amp;quot;&amp;quot;&lt;br /&gt;
    func 	displayScratchPad(),&lt;br /&gt;
    func 	new(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.input_string,&lt;br /&gt;
    func 	me.erase,&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.pm_trigger,&lt;br /&gt;
    func 	me.plusminus(),&lt;br /&gt;
    func 	me.clear(pressedTime),&lt;br /&gt;
    func 	me.erase(),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ListenerCollection ==&lt;br /&gt;
In order to update fields that are tied to a (potentially changing) property, fields that need a (potentially changing) property to compute their data can (and automatically will) register a property listener on the relevant properties whenever the relevant field is displayed. In order to unregister the listener for pages that are no longer displayed, the class CDU keeps a collection of the currently active listeners, such allowing the unregisterling for unneeded listeners.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ListenerCollection = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	add(prop, field_id, subpage_id, side, lsk_index),&lt;br /&gt;
    func 	clearAll(),&lt;br /&gt;
    func 	new(ptp=nil),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.listener_list,&lt;br /&gt;
    vector 	me.property_list,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==keyPressEvent==&lt;br /&gt;
In order to allow for a change in key effects, the CDU's 3D model's XML binds all key presses (and releases where appropriate) to a Nasal call to this function, giving the objects name (i.e. the keys name) as an argument. This name is then checked against the keys present in the KeyBinding hash (see below) and, if a match is found, that function is called.&lt;br /&gt;
&lt;br /&gt;
This function also keeps track of the current status of the plusminus, as this key either introduces a new char into the ScratchPad or toggles the last one entered.&lt;br /&gt;
&lt;br /&gt;
==KeyBinding==&lt;br /&gt;
This hash represents the current key binding. The CDU's Nasal code then overwrites these functions, effectively changing the effect of a key press. Note that the KeyBinding does not use the Button class's timing systems, but directly uses the a CDU.timer instance of the Timer class.&lt;br /&gt;
&lt;br /&gt;
= Helping Functions and Classes =&lt;br /&gt;
&lt;br /&gt;
Although written for the CDU framework, these functions are fairly general and might be useful for other code projects. Please feel free to reuse them.&lt;br /&gt;
&lt;br /&gt;
== prepend ==&lt;br /&gt;
  var prepend = func(vec, elements...) &lt;br /&gt;
This function is the counterpart to the Nasal provided append. Instead of adding stuff to the end of the vector &amp;lt;tt&amp;gt;vec&amp;lt;/tt&amp;gt; is adds them at the front, '''altering the original vector'''. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== stack ==&lt;br /&gt;
  var stack = func(elements...)&lt;br /&gt;
Instead of appending or prepending, this function simply stacks its argument vectors and '''returns a new vector''', leaving the original function arguments unaltered. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== latitude_to_string ==&lt;br /&gt;
  var latitude_to_string = func(lat_deg)&lt;br /&gt;
Take a Nasal scalar as input variable and return something like N23°14.8 . Actually, as the &amp;quot;°&amp;quot; seems to have some trouble in Helvetica, is returns something like N23*14.8. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== longitude_to_string ==&lt;br /&gt;
  var longitude_to_string = func(lon_deg)&lt;br /&gt;
Take a Nasal scalar as input variable and return something like E123°14.8 . Actually, as the &amp;quot;°&amp;quot; seems to have some trouble in Helvetica, is returns something like E123*14.8. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== Timer ==&lt;br /&gt;
A timer can be made as an instance of this class. Each timer provides the functions tic and toc, the later returning the delta time passed.&lt;br /&gt;
  var timer1 = Timer.new(); # uses /sim/time/elapsed-sec as a time source&lt;br /&gt;
  var timer2 = Timer.new(non_default_time_source_variable); # provide an alternate source of time&lt;br /&gt;
  &lt;br /&gt;
  timer1.tic(); # start the internal timer on the default time source&lt;br /&gt;
  &lt;br /&gt;
  var passed_time = timer1.toc(); # stop and reset the timer, get back the passed time in seconds.&lt;br /&gt;
This class is implemented in &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Button ==&lt;br /&gt;
As an example for the use of the before mentioned timer, this is a generic button class to be used for all kinds of GUI interfaces. Although not used in the CDU, it still might be useful for other projects that require buttons to do several different things - depending on how long it has been pushed.&lt;br /&gt;
&lt;br /&gt;
  var b_clr = Button.new(&amp;quot;CLEAR&amp;quot;); # make a new button and give it a name, stored in Button.name&lt;br /&gt;
  &lt;br /&gt;
  b_clr.addButtonAction(func() {print(&amp;quot;NO delay&amp;quot;);} ); # zero delay is the default. This function will be executed if no other criteria are met&lt;br /&gt;
  b_clr.addButtonAction(func() {print(&amp;quot;2s delay&amp;quot;);},2 ); # this function will be executed if the button has been pressed longer than 2 seconds when released.&lt;br /&gt;
  b_clr.addButtonAction(func() {print(&amp;quot;1s delay&amp;quot;);},1 ); # this function will be executed if the button has been pressed longer than 1 seconds when released.&lt;br /&gt;
&lt;br /&gt;
The corresponding XML code for your model.xml could look like this:&lt;br /&gt;
  &amp;lt;animation&amp;gt;&lt;br /&gt;
  	&amp;lt;type&amp;gt;pick&amp;lt;/type&amp;gt;&lt;br /&gt;
        &amp;lt;!-- UPDATE the name of the button object to match you case --&amp;gt;&lt;br /&gt;
  	&amp;lt;object-name&amp;gt;Btn.clr&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  	&amp;lt;action&amp;gt;&lt;br /&gt;
  		&amp;lt;button&amp;gt;0&amp;lt;/button&amp;gt;&lt;br /&gt;
  		&amp;lt;repeatable&amp;gt;false&amp;lt;/repeatable&amp;gt;  &lt;br /&gt;
  		&amp;lt;binding&amp;gt;&lt;br /&gt;
  			&amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
 			&amp;lt;nowiki&amp;gt;&amp;lt;!-- UPDATE the namespace --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  			&amp;lt;script&amp;gt;&amp;lt;![CDATA[NAMESPACE.b_clr.pressed();]]&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  		&amp;lt;/binding&amp;gt;&lt;br /&gt;
  		&amp;lt;mod-up&amp;gt;&lt;br /&gt;
  			&amp;lt;binding&amp;gt;&lt;br /&gt;
  				&amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
  				&amp;lt;nowiki&amp;gt;&amp;lt;!-- UPDATE the namespace --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  				&amp;lt;script&amp;gt;&amp;lt;![CDATA[NAMESPACE.b_clr.released();]]&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  			&amp;lt;/binding&amp;gt;&lt;br /&gt;
  		&amp;lt;/mod-up&amp;gt;&lt;br /&gt;
  	&amp;lt;/action&amp;gt;&lt;br /&gt;
  &amp;lt;/animation&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The sequence in which functions are added does not matter, note how the example created the 2 s before the 1 s functions. As a result of this, the button has to be released to work, i.e. currently it is not possible to make the button do something if the button has been pressed longer than X s and still is pressed.&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31571</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31571"/>
		<updated>2011-05-09T21:30:50Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Additional Infrastructure */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
These are the core classes in the CDU framework. The documentation should show a brief comment on what each variable or function is intended to do, particularly the ones that are important for the '''creation''' of an actual, content-filled CDU page.&lt;br /&gt;
&lt;br /&gt;
Although Nasal as such has no support for this, the internal stuff in a class is sectioned in three categories, borrowing language from &amp;lt;tt&amp;gt;C++&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Static:''' Stuff in this section is mainly identified by being made directly as part of the &amp;lt;tt&amp;gt;hash&amp;lt;/tt&amp;gt; (as opposed to being ''tagged on'' by the the &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; constructor. Elements in here also follow a ''camelCase'' type of notation, whereas ''members'' use an ''underscore_naming_convetion''. Please note that although meant to be comparable to statics, in hindsight a lot of them would be better placed in the member section Public...&lt;br /&gt;
&lt;br /&gt;
* '''Public:''' Elements in here are created from inside the &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; constructor and follow an ''underscore_naming_convetion''. In a perfect world these would only be accessing functions, as exposing variables is always prone for trouble when the time for a redesign comes... Elements in here should be the only ones used in the creation of a page - in a perfect world.&lt;br /&gt;
&lt;br /&gt;
* '''Private:''' Elements in here are created from inside the &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; constructor and follow an ''underscore_naming_convetion''. Although readable by everybody, access to these elements should be limited to functions in the static and public parts of the classes code. Particularly no page creation (user) code should need to access this information.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' I know that I violate these rules. Yes. But I have rewritten the framework to often to (at this point) care much about it - particularly as it seems to be working. Please, feel free to correct the Nasal code I have written (which might involve the pain of revisiting the page creation sections... Sorry for that.) [[User:Hcc23|Hcc23]] 14:45, 9 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	formatOutput(input_data),&lt;br /&gt;
    func 	getScreenTextVector(),&lt;br /&gt;
    func 	new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.used_properties,&lt;br /&gt;
    vector 	me.line_data,&lt;br /&gt;
    scalar 	me.line_string_length,&lt;br /&gt;
    func 	me.enable(),&lt;br /&gt;
    func 	me.disable(),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
A field holds two lines, the label and the data line, as well as information about what the associated line select key does.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Field = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	new(label,data,key_action=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
  &lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.used_properties(),&lt;br /&gt;
    func 	me.lsk_binding(),&lt;br /&gt;
    func 	me.enable_lsk(),&lt;br /&gt;
    func 	me.disable_lsk(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    (Line)	me.label_line,	&lt;br /&gt;
    (Line) 	me.data_line,&lt;br /&gt;
    scalar 	me.lsk_active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
A SubPage is actually the main element in the CDU framework. It holds the content via its fields and manages the updating of the CDU screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var SubPage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    (Field) 	blankField,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	updateField(field, side, lsk_index),	&lt;br /&gt;
    func 	displayFields(field_vector, side),&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	new(parent_base_page,name=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar      me.separator,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    func 	me.register_field(field_pos,field),&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.parent,&lt;br /&gt;
    scalar      me.title,&lt;br /&gt;
    scalar      me.status,&lt;br /&gt;
    vector 	me.left_field,&lt;br /&gt;
    vector      me.right_field,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
A BasePage is exactly that: a base to hold sub pages. A base page most closely represents the concept of a '''page''' in a CDU.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var BasePage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	regiserInPropTree(path)&lt;br /&gt;
    func 	new(name,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.active_sub_page_id,&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    vector 	me.sub_pages,&lt;br /&gt;
    scalar 	me.title,&lt;br /&gt;
    scalar 	me.status,&lt;br /&gt;
    &lt;br /&gt;
  };  &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
The CDU is the main class for the instrument. Each simulated CDU should have one and only one CDU instance associated to it. This is intended to support multiple CDUs showing different content in the future.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var CDU = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    func 	M_ERROR(message_string),&lt;br /&gt;
    func 	M_WARNING(message_string),&lt;br /&gt;
    func 	M_NOTE(message_string),&lt;br /&gt;
    func 	M_HINT(message_string),&lt;br /&gt;
  &lt;br /&gt;
    func 	updateDisplay(),&lt;br /&gt;
    scalar 	activeBasePageID,&lt;br /&gt;
  &lt;br /&gt;
    (ScratchPad) 		scratchPad,&lt;br /&gt;
    (Timer) 			timer,&lt;br /&gt;
    (ListenerCollection) 	listOfListeners,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Additional Infrastructure =&lt;br /&gt;
The previous section was more concerned with the conceptually necessary pieces for a/the CDU. This section introduces the other elements the framework introduces in order to code a functional CDU.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ScratchPad ==&lt;br /&gt;
&lt;br /&gt;
The ScratchPad is the input/output line in the CDU(s). The scratch pas as such is kind of different from the rest of the CDU(s) as the scratch pad messages are truly static, i.e. they happen to be displayed on all CDUs in the cockpit, no matter what the individual CDU is otherwise showing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ScratchPad = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	messages,&lt;br /&gt;
    scalar 	deleteString, # &amp;quot;DELETE&amp;quot;~&amp;quot;&amp;quot;&lt;br /&gt;
    func 	displayScratchPad(),&lt;br /&gt;
    func 	new(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.input_string,&lt;br /&gt;
    func 	me.erase,&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.pm_trigger,&lt;br /&gt;
    func 	me.plusminus(),&lt;br /&gt;
    func 	me.clear(pressedTime),&lt;br /&gt;
    func 	me.erase(),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ListenerCollection ==&lt;br /&gt;
In order to update fields that are tied to a (potentially changing) property, fields that need a (potentially changing) property to compute their data can (and automatically will) register a property listener on the relevant properties whenever the relevant field is displayed. In order to unregister the listener for pages that are no longer displayed, the class CDU keeps a collection of the currently active listeners, such allowing the unregisterling for unneeded listeners.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ListenerCollection = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	add(prop, field_id, subpage_id, side, lsk_index),&lt;br /&gt;
    func 	clearAll(),&lt;br /&gt;
    func 	new(ptp=nil),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.listener_list,&lt;br /&gt;
    vector 	me.property_list,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==keyPressEvent==&lt;br /&gt;
In order to allow for a change in key effects, the CDU's 3D model's XML binds all key presses (and releases where appropriate) to a Nasal call to this function, giving the objects name (i.e. the keys name) as an argument. This name is then checked against the keys present in the KeyBinding hash (see below) and, if a match is found, that function is called.&lt;br /&gt;
&lt;br /&gt;
This function also keeps track of the current status of the plusminus, as this key either introduces a new char into the ScratchPad or toggles the last one entered.&lt;br /&gt;
&lt;br /&gt;
==KeyBinding==&lt;br /&gt;
This hash represents the current key binding. The CDU's Nasal code then overwrites these functions, effectively changing the effect of a key press. Note that the KeyBinding does not use the Button class's timing systems, but directly uses the a CDU.timer instance of the Timer class.&lt;br /&gt;
&lt;br /&gt;
= Helping Functions and Classes =&lt;br /&gt;
&lt;br /&gt;
Although written for the CDU framework, these functions are fairly general and might be useful for other code projects. Please feel free to reuse them.&lt;br /&gt;
&lt;br /&gt;
== prepend ==&lt;br /&gt;
  var prepend = func(vec, elements...) &lt;br /&gt;
This function is the counterpart to the Nasal provided append. Instead of adding stuff to the end of the vector &amp;lt;tt&amp;gt;vec&amp;lt;/tt&amp;gt; is adds them at the front, '''altering the original vector'''. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== stack ==&lt;br /&gt;
  var stack = func(elements...)&lt;br /&gt;
Instead of appending or prepending, this function simply stacks its argument vectors and '''returns a new vector''', leaving the original function arguments unaltered. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== latitude_to_string ==&lt;br /&gt;
  var latitude_to_string = func(lat_deg)&lt;br /&gt;
Take a Nasal scalar as input variable and return something like N23°14.8 . Actually, as the &amp;quot;°&amp;quot; seems to have some trouble in Helvetica, is returns something like N23*14.8. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== longitude_to_string ==&lt;br /&gt;
  var longitude_to_string = func(lon_deg)&lt;br /&gt;
Take a Nasal scalar as input variable and return something like E123°14.8 . Actually, as the &amp;quot;°&amp;quot; seems to have some trouble in Helvetica, is returns something like E123*14.8. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== Timer ==&lt;br /&gt;
A timer can be made as an instance of this class. Each timer provides the functions tic and toc, the later returning the delta time passed.&lt;br /&gt;
  var timer1 = Timer.new(); # uses /sim/time/elapsed-sec as a time source&lt;br /&gt;
  var timer2 = Timer.new(non_default_time_source_variable); # provide an alternate source of time&lt;br /&gt;
  &lt;br /&gt;
  timer1.tic(); # start the internal timer on the default time source&lt;br /&gt;
  &lt;br /&gt;
  var passed_time = timer1.toc(); # stop and reset the timer, get back the passed time in seconds.&lt;br /&gt;
This class is implemented in &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Button ==&lt;br /&gt;
As an example for the use of the before mentioned timer, this is a generic button class to be used for all kinds of GUI interfaces. Although not used in the CDU, it still might be useful for other projects that require buttons to do several different things - depending on how long it has been pushed.&lt;br /&gt;
&lt;br /&gt;
  var b_clr = Button.new(&amp;quot;CLEAR&amp;quot;); # make a new button and give it a name, stored in Button.name&lt;br /&gt;
  &lt;br /&gt;
  b_clr.addButtonAction(func() {print(&amp;quot;NO delay&amp;quot;);} ); # zero delay is the default. This function will be executed if no other criteria are met&lt;br /&gt;
  b_clr.addButtonAction(func() {print(&amp;quot;2s delay&amp;quot;);},2 ); # this function will be executed if the button has been pressed longer than 2 seconds when released.&lt;br /&gt;
  b_clr.addButtonAction(func() {print(&amp;quot;1s delay&amp;quot;);},1 ); # this function will be executed if the button has been pressed longer than 1 seconds when released.&lt;br /&gt;
&lt;br /&gt;
The corresponding XML code for your model.xml could look like this:&lt;br /&gt;
  &amp;lt;animation&amp;gt;&lt;br /&gt;
  	&amp;lt;type&amp;gt;pick&amp;lt;/type&amp;gt;&lt;br /&gt;
        &amp;lt;!-- UPDATE the name of the button object to match you case --&amp;gt;&lt;br /&gt;
  	&amp;lt;object-name&amp;gt;Btn.clr&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  	&amp;lt;action&amp;gt;&lt;br /&gt;
  		&amp;lt;button&amp;gt;0&amp;lt;/button&amp;gt;&lt;br /&gt;
  		&amp;lt;repeatable&amp;gt;false&amp;lt;/repeatable&amp;gt;  &lt;br /&gt;
  		&amp;lt;binding&amp;gt;&lt;br /&gt;
  			&amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
 			&amp;lt;nowiki&amp;gt;&amp;lt;!-- UPDATE the namespace --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  			&amp;lt;script&amp;gt;&amp;lt;![CDATA[NAMESPACE.b_clr.pressed();]]&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  		&amp;lt;/binding&amp;gt;&lt;br /&gt;
  		&amp;lt;mod-up&amp;gt;&lt;br /&gt;
  			&amp;lt;binding&amp;gt;&lt;br /&gt;
  				&amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
  				&amp;lt;nowiki&amp;gt;&amp;lt;!-- UPDATE the namespace --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  				&amp;lt;script&amp;gt;&amp;lt;![CDATA[NAMESPACE.b_clr.released();]]&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  			&amp;lt;/binding&amp;gt;&lt;br /&gt;
  		&amp;lt;/mod-up&amp;gt;&lt;br /&gt;
  	&amp;lt;/action&amp;gt;&lt;br /&gt;
  &amp;lt;/animation&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The sequence in which functions are added does not matter, note how the example created the 2 s before the 1 s functions. As a result of this, the button has to be released to work, i.e. currently it is not possible to make the button do something if the button has been pressed longer than X s and still is pressed.&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=31570</id>
		<title>Howto:Coding a Boeing CDU</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=31570"/>
		<updated>2011-05-09T21:20:44Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* The Code Framework */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
[[User:Gijs|Gijs]] has started an effort to bring a generic Boeing [[CDU]] to [[FlightGear]]. This page tries to describe the coding for this effort.&lt;br /&gt;
&lt;br /&gt;
= The Sources =&lt;br /&gt;
The [[CDU]] is aimed to reside in '''$FGDATA/Aircraft/Instruments-3d/cdu/'''.&lt;br /&gt;
&lt;br /&gt;
'''Graphics''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_Cdu.ac&amp;lt;/tt&amp;gt;: This is a [[AC3D]] file, describing the 3D outline of the CDU model.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_brown.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_grey.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
&lt;br /&gt;
'''XML''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;: This is the main [[XML]] file, providing the direct interface between the 3D model and the code. This file also defines the keypress interactions and the positioning of the text to be displayed in the screen.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt;: An OSGText &amp;quot;model&amp;quot;, used as a baseline for the texts on the screen. Compare to &amp;lt;tt&amp;gt;README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Nasal''':&lt;br /&gt;
The Nasal part is composed of two sections, the framework (which a CDU content coder hopefully would not have to touch) ...&lt;br /&gt;
* &amp;lt;tt&amp;gt;cdu_page_framework.nas&amp;lt;/tt&amp;gt;: This is the main file of the CDU framework. It defines the main ''classes'' used for the CDU.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;: This file contains the Nasal relevant for the dispaly matrix. This code might be useful for other complex screen-based instruments.&lt;br /&gt;
* &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;: This file contains functions which I found useful for my project, but which are totally generic and could be used for other stuff as well.&lt;br /&gt;
* &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;: This file contains a rudimentary timer ''class'' and an example of how to incorporate this with a generic class for an instrument button, allowing the button to call different Nasal scripts, depending on how long it has been pressed. &lt;br /&gt;
* &amp;lt;tt&amp;gt;README&amp;lt;/tt&amp;gt;: Well, a readme.&lt;br /&gt;
... and the actual content implementation&lt;br /&gt;
* &amp;lt;tt&amp;gt;b777_cdu.nas&amp;lt;/tt&amp;gt;: This is the main [[Nasal]] script file to be edited by the ''user'' of the CDU Nasal framework.&lt;br /&gt;
* &amp;lt;tt&amp;gt;b777_cdu_page_XXXXXX.nas&amp;lt;/tt&amp;gt;: The content of the individual pages of the CDU.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' You can find the current version in my git repository at https://gitorious.org/~hcc23/fg/hcc23s-fgdata/trees/cdu-development [[User:Hcc23|Hcc23]] 16:13, 9 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Loading a CDU into an Aircraft ==&lt;br /&gt;
Here is how the CDU is loaded into the Boeing 777-200:&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;777-22ER-set.xml&amp;lt;/tt&amp;gt; the Nasal node is expanded as follows:&lt;br /&gt;
  &amp;lt;instrumentation&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
             &amp;lt;serviceable type=&amp;quot;bool&amp;quot;&amp;gt;true&amp;lt;/serviceable&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
  &amp;lt;instrumentation&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- GENERIC --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!--&lt;br /&gt;
  	      Every CDU needs these files in order to make use of the CDU Framework.&lt;br /&gt;
  	      It should not be necessary to alter these files in order to &amp;quot;just&amp;quot; make&lt;br /&gt;
  	      some CDU pages.&lt;br /&gt;
  	      Think of these files as &amp;quot;header files&amp;quot; or stuff that one uses to &lt;br /&gt;
  	      &amp;quot;inherit&amp;quot; from.&lt;br /&gt;
  	    --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/helping_functions.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/display_matrix.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/timer.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/cdu_page_framework.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- SPECIFIC --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- &lt;br /&gt;
  	      These files here provide the actual content of a CDU and a person &lt;br /&gt;
  	      who wants to create CDU pages needs to change, add, and alter these files.&lt;br /&gt;
  	      Think of these files as where the actuall instantiation happens.&lt;br /&gt;
  	    --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_menu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_index.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_ident.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_pos.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_approach.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_navData.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_navRadio.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_perf.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_thrustLim.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_takeoff.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
Note the difference in the framework files and the actual ''instance'' used for this aircraft. To code pages for the CDU, one would normally not have to mess with the framework files. [[User:Hcc23|Hcc23]]&lt;br /&gt;
&lt;br /&gt;
The 3D model is loaded from within  &amp;lt;tt&amp;gt;$FGDATA/Aircraft/777-200/Models/pedestal.xml&amp;lt;/tt&amp;gt; and the Nasal node is expanded as follows to accomplish that:&lt;br /&gt;
&lt;br /&gt;
     &amp;lt;model&amp;gt;&lt;br /&gt;
        &amp;lt;name&amp;gt;CDU1&amp;lt;/name&amp;gt;&lt;br /&gt;
        &amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/boeing_cdu.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
        &amp;lt;offsets&amp;gt;&lt;br /&gt;
            &amp;lt;x-m&amp;gt;-0.423&amp;lt;/x-m&amp;gt;&lt;br /&gt;
            &amp;lt;y-m&amp;gt;-0.175&amp;lt;/y-m&amp;gt;&lt;br /&gt;
            &amp;lt;z-m&amp;gt;0.559&amp;lt;/z-m&amp;gt;&lt;br /&gt;
            &amp;lt;pitch-deg&amp;gt;-60&amp;lt;/pitch-deg&amp;gt;&lt;br /&gt;
        &amp;lt;/offsets&amp;gt;&lt;br /&gt;
        &amp;lt;overlay&amp;gt;&lt;br /&gt;
            &amp;lt;texture&amp;gt;boeing_brown.png&amp;lt;/texture&amp;gt;&lt;br /&gt;
            &amp;lt;material&amp;gt;&lt;br /&gt;
                &amp;lt;emission&amp;gt;&lt;br /&gt;
                    &amp;lt;red&amp;gt;0.1&amp;lt;/red&amp;gt;&lt;br /&gt;
                    &amp;lt;green&amp;gt;0.1&amp;lt;/green&amp;gt;&lt;br /&gt;
                    &amp;lt;blue&amp;gt;0.1&amp;lt;/blue&amp;gt;&lt;br /&gt;
                &amp;lt;/emission&amp;gt;&lt;br /&gt;
            &amp;lt;/material&amp;gt;&lt;br /&gt;
        &amp;lt;/overlay&amp;gt;&lt;br /&gt;
    &amp;lt;/model&amp;gt;&lt;br /&gt;
    &amp;lt;animation&amp;gt;&lt;br /&gt;
        &amp;lt;type&amp;gt;scale&amp;lt;/type&amp;gt;&lt;br /&gt;
        &amp;lt;object-name&amp;gt;CDU1&amp;lt;/object-name&amp;gt;&lt;br /&gt;
        &amp;lt;x-offset&amp;gt;0.9&amp;lt;/x-offset&amp;gt;&lt;br /&gt;
        &amp;lt;y-offset&amp;gt;0.8&amp;lt;/y-offset&amp;gt;&lt;br /&gt;
        &amp;lt;z-offset&amp;gt;0.9&amp;lt;/z-offset&amp;gt;&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&amp;lt;center&amp;gt;&lt;br /&gt;
            &amp;lt;x-m&amp;gt;-0.423&amp;lt;/x-m&amp;gt;&lt;br /&gt;
            &amp;lt;y-m&amp;gt;-0.175&amp;lt;/y-m&amp;gt;&lt;br /&gt;
            &amp;lt;z-m&amp;gt;0.559&amp;lt;/z-m&amp;gt;&lt;br /&gt;
        &amp;lt;/center&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
    &amp;lt;/animation&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code loads one CDU, the B777-200 has three of them, all loaded in the same way.&lt;br /&gt;
&lt;br /&gt;
== 3D Graphics ==&lt;br /&gt;
The 3D model resides in the file '''&amp;lt;tt&amp;gt;$FGDATA/Models/Cockpit/Instruments-3d/boeing_cdu.ac&amp;lt;/tt&amp;gt;'''. This is a [[AC3D]] file format, but it should be importable by [[Blender]].&lt;br /&gt;
{|&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| [[File:CDU_3D_wireframe.png|thumb|270px|The wireframe of the 3D model and the corresponding coordinate system. ATTENTION: the axis are not right: RED is +X, GREEN is +Z, BLUE is -Y !]]&lt;br /&gt;
| [[File:CDU.png|thumb|270px|The texture of the CDU, a 512x512 PNG bitmap.]]&lt;br /&gt;
| [[File:CDU_3D_textures.png|thumb|270px|The resulting 3D model, after the textures have been added.]]&lt;br /&gt;
|}&lt;br /&gt;
The model also specifies the model internal coordinate system. It is indicated in the pictures through the corresponding axis: X (red), Y (green), and Z (blue). The origin of this coordinate system seems to coincide with the geometric center of the back plane of the [[CDU]], i.e. the YZ-plane is coplanar with the back of the [[CDU]]. The unit of the coordinate system is the SI unit ''Meter''.&lt;br /&gt;
&lt;br /&gt;
The 3D model has has a name assigned to each button. Via XML bindings these can be detected, so when a certain button is clicked, something happens. Currently not all buttons are functional and there is no real way of telling which will do something (other then pressing them and observing the reaction or reading the source code...)&lt;br /&gt;
&lt;br /&gt;
=== The Screen of the CDU ===&lt;br /&gt;
With respect to the model coordinate frame, the screen is the rectangle given by:&lt;br /&gt;
&lt;br /&gt;
  Top edge:   z= 0.111, x=0.004&lt;br /&gt;
  Lower edge: z= 0.019, x=0.004&lt;br /&gt;
  Left edge:  y=-0.051, x=0.004&lt;br /&gt;
  Right edge: y= 0.051, x=0.004&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The CDU Screen = &lt;br /&gt;
One of the major problems of the CDU is the representation of the actual screen. According to the Honeywell manual, the CDU utilized by Boeing has a fixed setup which could be captured by a matrix-like approach, i.e. a fixed number of rows and columns (each element holding one character) and an assigned format of that cell.&lt;br /&gt;
&lt;br /&gt;
This setup is replicated within the [[Nasal Display Matrix Framework]], which has been developed for this CDU.&lt;br /&gt;
&lt;br /&gt;
== Details of the (LCD) Screen ==&lt;br /&gt;
The LCD has '''14 lines''' with a total of '''24 characters per line'''. The page format is formatted as follows:&lt;br /&gt;
&lt;br /&gt;
* Title Field: The top line of the display area. Id identifies the subject or title of the data displayed on the page in view. It also identifies page number and the number of pages in series, e.g., &amp;lt;tt&amp;gt;1/2&amp;lt;/tt&amp;gt; identifies a page as the first in a series of two pages.&lt;br /&gt;
* Left Field: 6 pairs of lines, 11 characters per line. It extends from the left side of the screen to the center. The pilot has access to one line of each pair through a LSK (Line-Select Key) on the left side of the CDU. A line pair is made up of a label and a data line.&lt;br /&gt;
* Right Field: This field is similar to the left field, extending from the center of the screen to the right side. Pilot access is available by a LSK on the right side. &lt;br /&gt;
* Scratchpad: The bottom line of the display screen. This line displays alphanumeric data or messages. Data can be entered with the alphanumeric keys or the LSK, or by the FMC. Scratchpad entry cannot, normally, be made with a FMC message in the scratchpad. Scratchpad entries are independent of page selection, and remain until cleared even when page changes occur. Scratchpad data entries and erases affect only the associated CDU. Messages can appear and be erased on both CDUs simultaneously.&lt;br /&gt;
&lt;br /&gt;
For more details on the implementation of the display matrix, read the page on the [[Nasal Display Matrix Framework]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Code Framework =&lt;br /&gt;
&lt;br /&gt;
This is a rough overview on the internal framework of the CDU code. A more detailed descriptions can be found at the [[Nasal CDU Framework]] page.&lt;br /&gt;
&lt;br /&gt;
The CDU framework is implemented following some standard object-oriented ideas, completely implemented in Nasal. All variables are instantiated using &amp;lt;tt&amp;gt;var&amp;lt;/tt&amp;gt; so that the global namespace should not be tainted.&lt;br /&gt;
&lt;br /&gt;
The idea for the framework stems from the fact that a CDU is based upon the concept of ''pages'', some of which could occupy several screens. This, in conjunction with the idea of the ''fields'' (stipulated from the screen layout of the CDU) resulted in the following framework:&lt;br /&gt;
  CDU&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | | |-Line&lt;br /&gt;
  | | | |-Line&lt;br /&gt;
  | | | &lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |  |-Line&lt;br /&gt;
  | | |  |-Line&lt;br /&gt;
  | | |&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | | &lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | |&lt;br /&gt;
  | |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  |   |&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-...&lt;br /&gt;
Well, you get the idea....&lt;br /&gt;
&lt;br /&gt;
These four  ''classes'' (BasePage, SubPage, Field, Line) are defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;. The constructors are generally called &amp;lt;tt&amp;gt;.new()&amp;lt;/tt&amp;gt;, all ''members'' are created within the constructors, all ''static'' parts are implemented directly on the hash level.&lt;br /&gt;
&lt;br /&gt;
Beside these four classes the class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;) is used to house the actual text to be printed.&lt;br /&gt;
&lt;br /&gt;
All text is then kept internal to Nasal within the before-mentioned structure. The text is then also kept in the FlightGear property tree so that an interface to osgtext can be established via &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' There is a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable set in the CDU framework. Setting this variable to non-zero enables a bunch of console printouts, implemented via &amp;lt;tt&amp;gt;DEBUG&amp;gt;debug_level?print('....'):;&amp;lt;/tt&amp;gt; Furthermore, when calling a constructor, the parameter &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt; (for path-to-property) can be set, enabling some member variables of the classes to register themselves in the property tree, allowing an easier debugging during runtime. [[User:Hcc23|Hcc23]] 15:20, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
Maybe looking at the actual code is the easiest way of understanding how the framework works. (I also tried to be fairly explicit in my in-code comments, so looking at the sources might actually be helpful, too. [[User:Hcc23|Hcc23]] 15:46, 8 April 2011 (EDT))&lt;br /&gt;
&lt;br /&gt;
As the framework is separate from the ''instantiation'', let's focus on that as that is the part a ''user'' (i.e. content coder) should care most about. The initially relevant file for the Boeing 777-200 is &amp;lt;tt&amp;gt;b777_cdu.nas&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Preliminaries==&lt;br /&gt;
Initially some settings can/should be changed in &amp;lt;tt&amp;gt;b777_cdu.nas&amp;lt;/tt&amp;gt;. Most importantly these are the &amp;lt;tt&amp;gt;PROP&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variables.&lt;br /&gt;
&lt;br /&gt;
  #&lt;br /&gt;
  #   The variables PROP and DEBUG have already been defined in the&lt;br /&gt;
  #   cdu_page_framework but can  be redifined here in order to &lt;br /&gt;
  #   customize the desired behaviour.&lt;br /&gt;
  #&lt;br /&gt;
  &lt;br /&gt;
  var PROP = &amp;quot;/instrumentation/cdu&amp;quot;; 	# generic path to the properties of this CDU&lt;br /&gt;
  &lt;br /&gt;
  # DEBUG = 0; # NO messages&lt;br /&gt;
  # DEBUG = 1; # ERROR messages&lt;br /&gt;
  # DEBUG = 2; # ERROR, WARNING messages &lt;br /&gt;
  # DEBUG = 3; # ERROR, WARNING, NOTE messages&lt;br /&gt;
  var DEBUG = 2;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;PROP&amp;lt;/tt&amp;gt; determines where the CDU stores stuff in the property tree, &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt;  sets the level of verbosity of the console output. The default for &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; is 1, only printing errors. For content coding 2 might be more suitable. 3 and 4 really print a lot of stuff and should only be used when searching for bugs or other things that don't work as expected.&lt;br /&gt;
&lt;br /&gt;
In order to be more generic, it might be helpful to precheck for the FDM an aircraft is using. (This is only done here in order to reduce the number of getprop calls to /sim/flight-model.)&lt;br /&gt;
  &lt;br /&gt;
  # determine the flight dynamics model&lt;br /&gt;
  # options are: &lt;br /&gt;
  #   &amp;quot;yasim&amp;quot;&lt;br /&gt;
  #   &amp;quot;jsb&amp;quot;&lt;br /&gt;
  var FDM = getprop(&amp;quot;/sim/flight-model&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
Furthermore it might be helpful to start from a clean sheet:&lt;br /&gt;
&lt;br /&gt;
  # reset the display matrix in the property tree to &amp;quot;zero&amp;quot;.&lt;br /&gt;
  resetDisplayMatrix();&lt;br /&gt;
&lt;br /&gt;
==Starting with Base- and SubPages==&lt;br /&gt;
It all starts in &amp;lt;tt&amp;gt;b777_cdu.nas&amp;lt;/tt&amp;gt; as well. Use this file to create the Base- and corresponding SubPages before the content is created. Though technically possible to create the pages not here (but in the corresponding page's file), the detached approach is helpful as it prevents some issued with the &amp;lt;tt&amp;gt;home&amp;lt;/tt&amp;gt;-fields (more on that later).&lt;br /&gt;
&lt;br /&gt;
  #############################&lt;br /&gt;
  # BASE PAGES  and  SUB PAGES&lt;br /&gt;
  #############################&lt;br /&gt;
  #&lt;br /&gt;
  # As some pages might need access to others pages &amp;quot;home&amp;quot; field, it is&lt;br /&gt;
  # necessary to create all the base pages here so that the home fields&lt;br /&gt;
  # are already in place when some pages want to use it.&lt;br /&gt;
  #&lt;br /&gt;
  var page_menu 		= BasePage.new(&amp;quot;MENU&amp;quot;,PROP~&amp;quot;/page_menu&amp;quot;); &lt;br /&gt;
  var page_menu_default 	= SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
  KeyBinding[&amp;quot;MENU&amp;quot;] 	= page_menu.activate;&lt;br /&gt;
&lt;br /&gt;
This section creates the menu base page of the CDU. The constructor for base pages is this one:&lt;br /&gt;
  new: func(name,ptp=nil) {...};&lt;br /&gt;
What this essentially does is creating a container to house sub pages. The &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element is used as the title of the page (but this could be overwritten in a sub page), the &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;, if set, registers the base page at that path. (However, if the &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable is set, the the pages are registered by their internal ID in a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; path underneath the CDU.)&lt;br /&gt;
&lt;br /&gt;
When a base page constructor is called, it also creates a ''home''-field. This function can be used to make the corresponding base page the active page, i.e. display that page. As you can see above, the corresponding method of the MENU page is assigned to the related button of the CDU. &amp;lt;tt&amp;gt;KeyBinding&amp;lt;/tt&amp;gt; is defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;, for a list of the available buttons see &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
As outlined in the framework, each base page houses sub pages, which in turn house the fields (which hold the actual content). So we need to start by making a sub page:&lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_menu_default = SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
The constructor for a sub page looks like this:&lt;br /&gt;
  new: func(parent_base_page,name=nil,ptp=nil) {...};&lt;br /&gt;
The elements are fairly straight forward:&lt;br /&gt;
* parent_base_page: parent node of this sub page (which is a base page). Note that this is not the name of that page, but the actual page, i.e. put down the name of the variable you made earlier. Here, this is a sub page of &amp;lt;tt&amp;gt;page_menu&amp;lt;/tt&amp;gt;, i.e. the MENU page, which was made earlier.&lt;br /&gt;
* name: similar to the name of a base page, it is used as the title entry of the sub page. If a sub page has a name (which it doesn't need to have), the name of the sub page overwrites the name of the base page, such allowing for slightly different titles on each &amp;quot;screen&amp;quot; of a CDU &amp;quot;page&amp;quot;. Note, however, that the display of the page count is taken care of, i.e. you do not have to put that into the title.&lt;br /&gt;
* ptp: same as with the base page. Also identical, the registration is changed to registration by ID when the DEBUG variable is non-zero.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' For the time beeing, the debug registering procedure is permanent. [[User:Hcc23|Hcc23]] 17:20, 9 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
==Filling a SubPage (and the corresponding Fields)==&lt;br /&gt;
To continue the elaborate example for the menu page, here the code that makes this page:  &lt;br /&gt;
&lt;br /&gt;
  #######################&lt;br /&gt;
  # DETAILS PAGE MENU&lt;br /&gt;
  #######################&lt;br /&gt;
  # &lt;br /&gt;
  # TODO:&lt;br /&gt;
  # * pressing 1L only goes to the ident page on initialization of the FMC/CDU.&lt;br /&gt;
  #   If the CDU has been in use before, it goes back to whatever page was displayed before   &lt;br /&gt;
  # &lt;br /&gt;
  CDU.M_NOTE('Starting to make details for page '~'MENU');&lt;br /&gt;
  &lt;br /&gt;
  # create some properties&lt;br /&gt;
  setprop(page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,&amp;quot;ON&amp;quot;);&lt;br /&gt;
  setprop(page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_dsp_ctl&amp;quot;,&amp;quot;OFF&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
  # create the fields&lt;br /&gt;
  &lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,ScreenText.new(&amp;quot;&amp;lt;FMC     &amp;lt;ACT&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
  var toggle_efisCtl = toggle_OnOff_func(page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;);&lt;br /&gt;
  var field_efisCtl = Field.new(ScreenText.new(&amp;quot;EFIS CTL&amp;quot;,ScreenText[&amp;quot;white&amp;quot;]),[&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_off]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;lt;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_on]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
  ],toggle_efisCtl);&lt;br /&gt;
  &lt;br /&gt;
  var field_efis = Field.new(&amp;quot;&amp;quot;,ScreenText.new(&amp;quot;EFIS&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]));&lt;br /&gt;
  &lt;br /&gt;
  var toggle_efisDspCtl = toggle_OnOff_func(page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_dsp_ctl&amp;quot;);&lt;br /&gt;
  var field_efisDspCtl = Field.new(ScreenText.new(&amp;quot;DSP CTL&amp;quot;,ScreenText[&amp;quot;white&amp;quot;]),[&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_dsp_ctl&amp;quot;,toggle_OnOff_off]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;lt;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_dsp_ctl&amp;quot;,toggle_OnOff_on]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
  ],toggle_efisDspCtl);&lt;br /&gt;
  &lt;br /&gt;
  var field_maintInfo = Field.new(ScreenText.new(&amp;quot;MAINT INFO&amp;quot;,ScreenText[&amp;quot;white&amp;quot;]),ScreenText.new(&amp;quot;DISPLAY&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]));&lt;br /&gt;
  var field_memory = Field.new(&amp;quot;&amp;quot;,ScreenText.new(&amp;quot;MEMORY&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]));&lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage&lt;br /&gt;
  page_menu_default.register_field(&amp;quot;1L&amp;quot;,field_fmc);&lt;br /&gt;
  &lt;br /&gt;
  page_menu_default.register_field(&amp;quot;1R&amp;quot;,field_efisCtl);&lt;br /&gt;
  page_menu_default.register_field(&amp;quot;2R&amp;quot;,field_efis);&lt;br /&gt;
  page_menu_default.register_field(&amp;quot;3R&amp;quot;,field_efisDspCtl);&lt;br /&gt;
  page_menu_default.register_field(&amp;quot;5R&amp;quot;,field_maintInfo);&lt;br /&gt;
  page_menu_default.register_field(&amp;quot;6R&amp;quot;,field_memory);&lt;br /&gt;
  &lt;br /&gt;
  #activate the sub page (and display it consequentially)&lt;br /&gt;
  #DEBUG?page_menu_default.activate():;&lt;br /&gt;
  &lt;br /&gt;
  # activate the MENU page as the initial page of the CDU&lt;br /&gt;
  page_menu.activate();&lt;br /&gt;
  &lt;br /&gt;
&lt;br /&gt;
This code section starts to fill in the details of the page MENU. It starts by setting up some properties that will later on be used to hold data for a toggle field.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Theoretically the CDU as such should not hold this data, as this is all FMS stuff - which the CDU only displays. But in lieu of knowing whether (or where) such a content would/should live, I created it within the CDU.[[User:Hcc23|Hcc23]] 17:20, 9 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
After a sub page has been made, one needs to make fields to actually hold content:&lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,ScreenText.new(&amp;quot;&amp;lt;FMC     &amp;lt;ACT&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
This part creates a field, the field constructor is:&lt;br /&gt;
  new: func(label,data,key_action=nil,ptp=nil) {...};&lt;br /&gt;
This constructor is a little more complex than the previous ones:&lt;br /&gt;
* &amp;lt;tt&amp;gt;label&amp;lt;/tt&amp;gt;: the entry for the label line (the top line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;data&amp;lt;/tt&amp;gt;: the entry for data line (the lower line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;: as fields have an line select key associated with them, &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;, a function element, determines what happens when the LSK next to the data line is pressed.&lt;br /&gt;
* &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;: registering the field. As for base and sub pages, a non-zero DEBUG changes the ptp.&lt;br /&gt;
&lt;br /&gt;
In order to make the construction of a field a little more convenient, some very limited type of constructor overloading is incorporated. Both lines could be initialized with either an element of type &amp;lt;tt&amp;gt;ScreenText.new()&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;), i.e. a hash, or it can be initialized with a vector of ScreenText elements, i.e. with &amp;lt;tt&amp;gt;[ScreenText.new() ScreenText.new() ...]&amp;lt;/tt&amp;gt;, or it could be initialized with just a string, i.e. &amp;lt;tt&amp;gt;&amp;quot;ABCD&amp;quot;&amp;lt;/tt&amp;gt;. In the last case, the provided string will be used to internally create a &amp;lt;tt&amp;gt;ScreenText.new(input_string,ScreenText[&amp;quot;white&amp;quot;])&amp;lt;/tt&amp;gt; from it.&lt;br /&gt;
&lt;br /&gt;
Later in the code this field is then registered to the corresponding subpage via &lt;br /&gt;
  # register the fields in the subpage&lt;br /&gt;
  page_menu_default.register_field(&amp;quot;1L&amp;quot;,field_fmc);&lt;br /&gt;
&lt;br /&gt;
This part of the code puts this field into the top-left position in the sub page. Each sub page has two columns (L and R) of six elements (1-6) each. The columns are 1-indexed.&lt;br /&gt;
&lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_menu_default.activate();&lt;br /&gt;
&lt;br /&gt;
This part activates this sup page. SubPages as well as BasePages can be activated. The later then displays the currently acitve subpage of that base page, the former directly shows this page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Toggle Fields===&lt;br /&gt;
The MENU page has some fields that simply show an entry which can be toggled, say between &amp;quot;on&amp;quot; and &amp;quot;off&amp;quot;.  Here is the code that did that:&lt;br /&gt;
&lt;br /&gt;
  var toggle_efisCtl = toggle_OnOff_func(page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;);&lt;br /&gt;
  var field_efisCtl = Field.new(ScreenText.new(&amp;quot;EFIS CTL&amp;quot;,ScreenText[&amp;quot;white&amp;quot;]),[&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_off]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;lt;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
    ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_on]),&lt;br /&gt;
    ScreenText.new(&amp;quot;&amp;gt;&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]),&lt;br /&gt;
  ],toggle_efisCtl);&lt;br /&gt;
&lt;br /&gt;
Somewhere at the bottom of &amp;lt;tt&amp;gt;b777_cdu.nas&amp;lt;/tt&amp;gt; there are some little helper functions that make this code easier to replicate (at least for the &amp;quot;ON/OFF&amp;quot; case).&lt;br /&gt;
&lt;br /&gt;
So what happens is two-fold:&lt;br /&gt;
# a functionis made that is bound to the line select key of that field. &amp;lt;tt&amp;gt;toggle_OnOff_func&amp;lt;/tt&amp;gt; creates &amp;lt;tt&amp;gt;toggle_efisCtl&amp;lt;/tt&amp;gt; for that purpose and &amp;lt;tt&amp;gt;toggle_efisCtl&amp;lt;/tt&amp;gt; is made to alter between &amp;quot;ON&amp;quot; and &amp;quot;OFF&amp;quot;, depending on the value of &amp;lt;tt&amp;gt;page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
# a field is made (&amp;lt;tt&amp;gt;field_efisCtl&amp;lt;/tt&amp;gt;) that houses the data and it's formatting.&lt;br /&gt;
&lt;br /&gt;
The field makes use of several things:&lt;br /&gt;
* the label line of the field is a simple ScreenText, always displaying EFIS CTL in small white characters.&lt;br /&gt;
* the data line of the field is represented using an vector of ScreenTexts, allowing for individual formatting of the different parts.&lt;br /&gt;
* the ScreenText used in the label makes use of an advanced formatting vector wich allows the content to be bound to the decision value &amp;lt;tt&amp;gt;page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
What effectively happens is that &amp;lt;tt&amp;gt;[&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_off]&amp;lt;/tt&amp;gt; creates a ScreeText output that &lt;br /&gt;
* is dependetn on a property, &amp;lt;tt&amp;gt;page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;&amp;lt;/tt&amp;gt; in this case&lt;br /&gt;
* the value of that property is then modified by the funciotn &amp;lt;tt&amp;gt;toggle_OnOff_off&amp;lt;/tt&amp;gt;&lt;br /&gt;
* the output of that function is then formatted according to &amp;lt;tt&amp;gt;&amp;quot;%s&amp;quot;&amp;lt;/tt&amp;gt;, i.e. simply print.&lt;br /&gt;
Internally the following is happening:&lt;br /&gt;
  ScreenText.new([&amp;quot;%s&amp;quot;,page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;,toggle_OnOff_off])&lt;br /&gt;
is equivalent to&lt;br /&gt;
  ScreenText.new(sprintf(&amp;quot;%s&amp;quot;,toggle_OnOff_off(getprop(page_menu_default.ptp~&amp;quot;/data&amp;quot;~&amp;quot;/efis_ctl&amp;quot;)));&lt;br /&gt;
Furthermore, the toggle function changes the &amp;lt;tt&amp;gt;style&amp;lt;/tt&amp;gt; parameter of the ScreenText to alter between small font white characters (&amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt;) and large font green characters (&amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN&amp;quot;]&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
More on this can be found on the [[Nasal Display Matrix Framework]] page.&lt;br /&gt;
&lt;br /&gt;
= The Property Tree =&lt;br /&gt;
&lt;br /&gt;
The [[CDU]] also has some properties in the general [[FlightGear]] [[Property Tree]].&lt;br /&gt;
In general it is located in &amp;lt;code&amp;gt;/instrumentation/cdu/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= A Brief History of the Boeing CDU in FlightGear =&lt;br /&gt;
Find some more information on the [[CDU]] at these pages:&lt;br /&gt;
* [[CDU]]&lt;br /&gt;
* [[Howto: Implement a Control Display Unit]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=31569</id>
		<title>Howto:Coding a Boeing CDU</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=31569"/>
		<updated>2011-05-09T20:20:55Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
[[User:Gijs|Gijs]] has started an effort to bring a generic Boeing [[CDU]] to [[FlightGear]]. This page tries to describe the coding for this effort.&lt;br /&gt;
&lt;br /&gt;
= The Sources =&lt;br /&gt;
The [[CDU]] is aimed to reside in '''$FGDATA/Aircraft/Instruments-3d/cdu/'''.&lt;br /&gt;
&lt;br /&gt;
'''Graphics''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_Cdu.ac&amp;lt;/tt&amp;gt;: This is a [[AC3D]] file, describing the 3D outline of the CDU model.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_brown.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_grey.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
&lt;br /&gt;
'''XML''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;: This is the main [[XML]] file, providing the direct interface between the 3D model and the code. This file also defines the keypress interactions and the positioning of the text to be displayed in the screen.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt;: An OSGText &amp;quot;model&amp;quot;, used as a baseline for the texts on the screen. Compare to &amp;lt;tt&amp;gt;README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Nasal''':&lt;br /&gt;
The Nasal part is composed of two sections, the framework (which a CDU content coder hopefully would not have to touch) ...&lt;br /&gt;
* &amp;lt;tt&amp;gt;cdu_page_framework.nas&amp;lt;/tt&amp;gt;: This is the main file of the CDU framework. It defines the main ''classes'' used for the CDU.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;: This file contains the Nasal relevant for the dispaly matrix. This code might be useful for other complex screen-based instruments.&lt;br /&gt;
* &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;: This file contains functions which I found useful for my project, but which are totally generic and could be used for other stuff as well.&lt;br /&gt;
* &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;: This file contains a rudimentary timer ''class'' and an example of how to incorporate this with a generic class for an instrument button, allowing the button to call different Nasal scripts, depending on how long it has been pressed. &lt;br /&gt;
* &amp;lt;tt&amp;gt;README&amp;lt;/tt&amp;gt;: Well, a readme.&lt;br /&gt;
... and the actual content implementation&lt;br /&gt;
* &amp;lt;tt&amp;gt;b777_cdu.nas&amp;lt;/tt&amp;gt;: This is the main [[Nasal]] script file to be edited by the ''user'' of the CDU Nasal framework.&lt;br /&gt;
* &amp;lt;tt&amp;gt;b777_cdu_page_XXXXXX.nas&amp;lt;/tt&amp;gt;: The content of the individual pages of the CDU.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' You can find the current version in my git repository at https://gitorious.org/~hcc23/fg/hcc23s-fgdata/trees/cdu-development [[User:Hcc23|Hcc23]] 16:13, 9 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Loading a CDU into an Aircraft ==&lt;br /&gt;
Here is how the CDU is loaded into the Boeing 777-200:&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;777-22ER-set.xml&amp;lt;/tt&amp;gt; the Nasal node is expanded as follows:&lt;br /&gt;
  &amp;lt;instrumentation&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
             &amp;lt;serviceable type=&amp;quot;bool&amp;quot;&amp;gt;true&amp;lt;/serviceable&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
  &amp;lt;instrumentation&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- GENERIC --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!--&lt;br /&gt;
  	      Every CDU needs these files in order to make use of the CDU Framework.&lt;br /&gt;
  	      It should not be necessary to alter these files in order to &amp;quot;just&amp;quot; make&lt;br /&gt;
  	      some CDU pages.&lt;br /&gt;
  	      Think of these files as &amp;quot;header files&amp;quot; or stuff that one uses to &lt;br /&gt;
  	      &amp;quot;inherit&amp;quot; from.&lt;br /&gt;
  	    --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/helping_functions.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/display_matrix.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/timer.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/cdu_page_framework.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- SPECIFIC --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- &lt;br /&gt;
  	      These files here provide the actual content of a CDU and a person &lt;br /&gt;
  	      who wants to create CDU pages needs to change, add, and alter these files.&lt;br /&gt;
  	      Think of these files as where the actuall instantiation happens.&lt;br /&gt;
  	    --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_menu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_index.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_ident.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_pos.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_approach.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_navData.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_navRadio.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_perf.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_thrustLim.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_takeoff.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
Note the difference in the framework files and the actual ''instance'' used for this aircraft. To code pages for the CDU, one would normally not have to mess with the framework files. [[User:Hcc23|Hcc23]]&lt;br /&gt;
&lt;br /&gt;
The 3D model is loaded from within  &amp;lt;tt&amp;gt;$FGDATA/Aircraft/777-200/Models/pedestal.xml&amp;lt;/tt&amp;gt; and the Nasal node is expanded as follows to accomplish that:&lt;br /&gt;
&lt;br /&gt;
     &amp;lt;model&amp;gt;&lt;br /&gt;
        &amp;lt;name&amp;gt;CDU1&amp;lt;/name&amp;gt;&lt;br /&gt;
        &amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/boeing_cdu.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
        &amp;lt;offsets&amp;gt;&lt;br /&gt;
            &amp;lt;x-m&amp;gt;-0.423&amp;lt;/x-m&amp;gt;&lt;br /&gt;
            &amp;lt;y-m&amp;gt;-0.175&amp;lt;/y-m&amp;gt;&lt;br /&gt;
            &amp;lt;z-m&amp;gt;0.559&amp;lt;/z-m&amp;gt;&lt;br /&gt;
            &amp;lt;pitch-deg&amp;gt;-60&amp;lt;/pitch-deg&amp;gt;&lt;br /&gt;
        &amp;lt;/offsets&amp;gt;&lt;br /&gt;
        &amp;lt;overlay&amp;gt;&lt;br /&gt;
            &amp;lt;texture&amp;gt;boeing_brown.png&amp;lt;/texture&amp;gt;&lt;br /&gt;
            &amp;lt;material&amp;gt;&lt;br /&gt;
                &amp;lt;emission&amp;gt;&lt;br /&gt;
                    &amp;lt;red&amp;gt;0.1&amp;lt;/red&amp;gt;&lt;br /&gt;
                    &amp;lt;green&amp;gt;0.1&amp;lt;/green&amp;gt;&lt;br /&gt;
                    &amp;lt;blue&amp;gt;0.1&amp;lt;/blue&amp;gt;&lt;br /&gt;
                &amp;lt;/emission&amp;gt;&lt;br /&gt;
            &amp;lt;/material&amp;gt;&lt;br /&gt;
        &amp;lt;/overlay&amp;gt;&lt;br /&gt;
    &amp;lt;/model&amp;gt;&lt;br /&gt;
    &amp;lt;animation&amp;gt;&lt;br /&gt;
        &amp;lt;type&amp;gt;scale&amp;lt;/type&amp;gt;&lt;br /&gt;
        &amp;lt;object-name&amp;gt;CDU1&amp;lt;/object-name&amp;gt;&lt;br /&gt;
        &amp;lt;x-offset&amp;gt;0.9&amp;lt;/x-offset&amp;gt;&lt;br /&gt;
        &amp;lt;y-offset&amp;gt;0.8&amp;lt;/y-offset&amp;gt;&lt;br /&gt;
        &amp;lt;z-offset&amp;gt;0.9&amp;lt;/z-offset&amp;gt;&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&amp;lt;center&amp;gt;&lt;br /&gt;
            &amp;lt;x-m&amp;gt;-0.423&amp;lt;/x-m&amp;gt;&lt;br /&gt;
            &amp;lt;y-m&amp;gt;-0.175&amp;lt;/y-m&amp;gt;&lt;br /&gt;
            &amp;lt;z-m&amp;gt;0.559&amp;lt;/z-m&amp;gt;&lt;br /&gt;
        &amp;lt;/center&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
    &amp;lt;/animation&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code loads one CDU, the B777-200 has three of them, all loaded in the same way.&lt;br /&gt;
&lt;br /&gt;
== 3D Graphics ==&lt;br /&gt;
The 3D model resides in the file '''&amp;lt;tt&amp;gt;$FGDATA/Models/Cockpit/Instruments-3d/boeing_cdu.ac&amp;lt;/tt&amp;gt;'''. This is a [[AC3D]] file format, but it should be importable by [[Blender]].&lt;br /&gt;
{|&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| [[File:CDU_3D_wireframe.png|thumb|270px|The wireframe of the 3D model and the corresponding coordinate system. ATTENTION: the axis are not right: RED is +X, GREEN is +Z, BLUE is -Y !]]&lt;br /&gt;
| [[File:CDU.png|thumb|270px|The texture of the CDU, a 512x512 PNG bitmap.]]&lt;br /&gt;
| [[File:CDU_3D_textures.png|thumb|270px|The resulting 3D model, after the textures have been added.]]&lt;br /&gt;
|}&lt;br /&gt;
The model also specifies the model internal coordinate system. It is indicated in the pictures through the corresponding axis: X (red), Y (green), and Z (blue). The origin of this coordinate system seems to coincide with the geometric center of the back plane of the [[CDU]], i.e. the YZ-plane is coplanar with the back of the [[CDU]]. The unit of the coordinate system is the SI unit ''Meter''.&lt;br /&gt;
&lt;br /&gt;
The 3D model has has a name assigned to each button. Via XML bindings these can be detected, so when a certain button is clicked, something happens. Currently not all buttons are functional and there is no real way of telling which will do something (other then pressing them and observing the reaction or reading the source code...)&lt;br /&gt;
&lt;br /&gt;
=== The Screen of the CDU ===&lt;br /&gt;
With respect to the model coordinate frame, the screen is the rectangle given by:&lt;br /&gt;
&lt;br /&gt;
  Top edge:   z= 0.111, x=0.004&lt;br /&gt;
  Lower edge: z= 0.019, x=0.004&lt;br /&gt;
  Left edge:  y=-0.051, x=0.004&lt;br /&gt;
  Right edge: y= 0.051, x=0.004&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The CDU Screen = &lt;br /&gt;
One of the major problems of the CDU is the representation of the actual screen. According to the Honeywell manual, the CDU utilized by Boeing has a fixed setup which could be captured by a matrix-like approach, i.e. a fixed number of rows and columns (each element holding one character) and an assigned format of that cell.&lt;br /&gt;
&lt;br /&gt;
This setup is replicated within the [[Nasal Display Matrix Framework]], which has been developed for this CDU.&lt;br /&gt;
&lt;br /&gt;
== Details of the (LCD) Screen ==&lt;br /&gt;
The LCD has '''14 lines''' with a total of '''24 characters per line'''. The page format is formatted as follows:&lt;br /&gt;
&lt;br /&gt;
* Title Field: The top line of the display area. Id identifies the subject or title of the data displayed on the page in view. It also identifies page number and the number of pages in series, e.g., &amp;lt;tt&amp;gt;1/2&amp;lt;/tt&amp;gt; identifies a page as the first in a series of two pages.&lt;br /&gt;
* Left Field: 6 pairs of lines, 11 characters per line. It extends from the left side of the screen to the center. The pilot has access to one line of each pair through a LSK (Line-Select Key) on the left side of the CDU. A line pair is made up of a label and a data line.&lt;br /&gt;
* Right Field: This field is similar to the left field, extending from the center of the screen to the right side. Pilot access is available by a LSK on the right side. &lt;br /&gt;
* Scratchpad: The bottom line of the display screen. This line displays alphanumeric data or messages. Data can be entered with the alphanumeric keys or the LSK, or by the FMC. Scratchpad entry cannot, normally, be made with a FMC message in the scratchpad. Scratchpad entries are independent of page selection, and remain until cleared even when page changes occur. Scratchpad data entries and erases affect only the associated CDU. Messages can appear and be erased on both CDUs simultaneously.&lt;br /&gt;
&lt;br /&gt;
For more details on the implementation of the display matrix, read the page on the [[Nasal Display Matrix Framework]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Code Framework =&lt;br /&gt;
&lt;br /&gt;
This is a rough overview on the internal framework of the CDU code. A more detailed descriptions can be found at the [[Nasal CDU Framework]] page.&lt;br /&gt;
&lt;br /&gt;
The CDU framework is implemented following some standard object-oriented ideas, completely implemented in Nasal. All variables are instantiated using &amp;lt;tt&amp;gt;var&amp;lt;/tt&amp;gt; so that the global namespace should not be tainted.&lt;br /&gt;
&lt;br /&gt;
The idea for the framework stems from the fact that a CDU is based upon the concept of ''pages'', some of which could occupy several screens. This, in conjunction with the idea of the ''fields'' (stipulated from the screen layout of the CDU) resulted in the following framework:&lt;br /&gt;
  CDU&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | | |-Line&lt;br /&gt;
  | | | |-Line&lt;br /&gt;
  | | | &lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |  |-Line&lt;br /&gt;
  | | |  |-Line&lt;br /&gt;
  | | |&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | | &lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | |&lt;br /&gt;
  | |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  |   |&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-...&lt;br /&gt;
Well, you get the idea....&lt;br /&gt;
&lt;br /&gt;
These four  ''classes'' (BasePage, SubPage, Field, Line) are defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;. The constructors are generally called &amp;lt;tt&amp;gt;.new()&amp;lt;/tt&amp;gt;, all ''members'' are created within the constructors, all ''static'' parts are implemented directly on the hash level.&lt;br /&gt;
&lt;br /&gt;
Beside these four classes the class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;) is used to house the actual text to be printed.&lt;br /&gt;
&lt;br /&gt;
All text is then kept internal to Nasal within the before-mentioned structure. The text is then also kept in the FlightGear property tree so that an interface to osgtext can be established via &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' There is a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable set in the CDU framework. Setting this variable to non-zero enables a bunch of console printouts, implemented via &amp;lt;tt&amp;gt;DEBUG&amp;gt;debug_level?print('....'):;&amp;lt;/tt&amp;gt; Furthermore, when calling a constructor, the parameter &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt; (for path-to-property) can be set, enabling some member variables of the classes to register themselves in the property tree, allowing an easier debugging during runtime. [[User:Hcc23|Hcc23]] 15:20, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
Maybe looking at the actual code is the easiest way of understanding how the framework works. (I also tried to be fairly explicit in my in-code comments, so looking at the sources should actually be helpful, too. [[User:Hcc23|Hcc23]] 15:46, 8 April 2011 (EDT))&lt;br /&gt;
&lt;br /&gt;
As the framework is separate from the ''instanciation'', let's focus on that as that is the part a ''user'' should care mostly about. The relevant file for the Boeing 777-200 is &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Preliminaries===&lt;br /&gt;
  #####################################################&lt;br /&gt;
  # These variables have already been defined in &lt;br /&gt;
  # cdu_page_framework but can (?) be redifined here &lt;br /&gt;
  # for slightly changed versions.&lt;br /&gt;
  #####################################################&lt;br /&gt;
  &lt;br /&gt;
  var ROWS = 14; 	# the number of lines the CDU has&lt;br /&gt;
  var COLS = 24; 	# the number of characters each line can hold&lt;br /&gt;
  var PROP = &amp;quot;/instrumentation/cdu&amp;quot;; 	# generic path to the properties of this CDU&lt;br /&gt;
  var DEBUG = 1; # enable a more verbose &amp;quot;debug&amp;quot; mode, i.e. register all kinds of stuff in the property tree&lt;br /&gt;
  &lt;br /&gt;
  resetDisplayMatrix();&lt;br /&gt;
This essential defines the size of the dispaly matrix, enables the debug printout and clears the display matrix in the property tree.&lt;br /&gt;
(&amp;lt;tt&amp;gt;resetDisplayMatrix();&amp;lt;/tt&amp;gt; fills the complete display matrix with spaces ( ) and also set the style to &amp;lt;tt&amp;gt;&amp;quot;off&amp;quot;&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
===Making the BasePages===&lt;br /&gt;
  # make the pages&lt;br /&gt;
  var page_menu      = BasePage.new(&amp;quot;MENU&amp;quot;,PROP~&amp;quot;/page_menu&amp;quot;); &lt;br /&gt;
  KeyBinding[&amp;quot;MENU&amp;quot;] = func() {page_menu.displayPage(); }; # Note : do NOT forget to wrap displayPage with a function!&lt;br /&gt;
  var page_index     = BasePage.new(&amp;quot;INDEX&amp;quot;,PROP~&amp;quot;/page_index&amp;quot;); &lt;br /&gt;
  var page_ident     = BasePage.new(&amp;quot;IDENT&amp;quot;,PROP~&amp;quot;/page_ident&amp;quot;); &lt;br /&gt;
  var page_pos       = BasePage.new(&amp;quot;POS&amp;quot;,PROP~&amp;quot;/page_pos&amp;quot;); &lt;br /&gt;
  var page_perf      = BasePage.new(&amp;quot;PERF&amp;quot;,PROP~&amp;quot;/page_perf&amp;quot;); &lt;br /&gt;
  var page_thrustLim = BasePage.new(&amp;quot;THRUST LIM&amp;quot;,PROP~&amp;quot;/page_thurstLim&amp;quot;); &lt;br /&gt;
  var page_takeoff   = BasePage.new(&amp;quot;TAKEOFF&amp;quot;,PROP~&amp;quot;/page_takeoff&amp;quot;); &lt;br /&gt;
  var page_approach  = BasePage.new(&amp;quot;APPROACH&amp;quot;,PROP~&amp;quot;/page_approach&amp;quot;); &lt;br /&gt;
  var page_navData   = BasePage.new(&amp;quot;NAV DATA&amp;quot;,PROP~&amp;quot;/page_navData&amp;quot;); &lt;br /&gt;
  var page_maint     = BasePage.new(&amp;quot;MAINT&amp;quot;,PROP~&amp;quot;/page_maint&amp;quot;); &lt;br /&gt;
This section creates the base pages of the CDU. The constructor for base pages is this one:&lt;br /&gt;
  new: func(name,ptp=nil) {...};&lt;br /&gt;
What this essentially does is creating a container to house sub pages. The &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element is used as the title of the page (but this could be overwritten in a sub page), the &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;, if set, registers the base page at that path. (However, if the &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable is set, the the pages are registered by their internal ID in a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; path underneath the CDU.)&lt;br /&gt;
&lt;br /&gt;
When a base page constructor is called, it also creates a ''home''-method. This function can be used to make the corresponding base page the active page, i.e. display that page. As you can see above, the corresponding method of the MENU page is assigned to the related button of the CDU. &amp;lt;tt&amp;gt;KeyBinding&amp;lt;/tt&amp;gt; is defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;, for a list of the available buttons see &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Making a SubPage (and the corresponding Fields)===&lt;br /&gt;
  #######################&lt;br /&gt;
  # DETAILS PAGE MENU&lt;br /&gt;
  #######################&lt;br /&gt;
  #&lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make details for page &amp;quot;~&amp;quot;MENU&amp;quot;):;&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_menu_default = SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,&amp;quot;FMC&amp;quot;,page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
  &lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_menu_default.activate();&lt;br /&gt;
This code section starts to fill in the details of the page MENU. As outlined in the framework, each base page houses sub pages, which in turn house the fields (which hold the actual content). So we need to start by making a sub page:&lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_menu_default = SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
The constructor for a sub page looks like this:&lt;br /&gt;
  new: func(parent_base_page,name=nil,ptp=nil) {...};&lt;br /&gt;
The elements are fairly straight forward:&lt;br /&gt;
* parent_base_page: parent node of this sub page (which is a base page). Note that this is not the name of that page, but the actual page, i.e. put down the name of the variable you made earlier. Here, this is a sub page of &amp;lt;tt&amp;gt;page_menu&amp;lt;/tt&amp;gt;, i.e. the MENU page, which was made earlier.&lt;br /&gt;
* name: similar to the name of a base page, it is used as the title entry of the sub page. If a sub page has a name (which it doesn't need to have), the name of the sub page overwrites the name of the base page, such allowing for slightly different titles on each &amp;quot;screen&amp;quot; of a CDU &amp;quot;page&amp;quot;. Note, however, that the display of the page count is taken care of, i.e. you do not have to put that into the title.&lt;br /&gt;
* ptp: same as with the base page. Also identical, the registration is changed to registration by ID when the DEBUG variable is non-zero.&lt;br /&gt;
&lt;br /&gt;
After a sub page has been made, one needs to make fields to actually hold content:&lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,&amp;quot;FMC&amp;quot;,page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
The first part creates a field, the field constructor is:&lt;br /&gt;
  new: func(label,data,key_action=nil,ptp=nil) {...};&lt;br /&gt;
This constructor is a little more complex than the previous ones:&lt;br /&gt;
* &amp;lt;tt&amp;gt;label&amp;lt;/tt&amp;gt;: the entry for the label line (the top line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;data&amp;lt;/tt&amp;gt;: the entry for data line (the lower line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;: as fields have an line select key associated with them, &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;, a function element, determines what happens when the LSK next to the data line is pressed.&lt;br /&gt;
* &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;: registering the field. As for base and sub pages, a non-zero DEBUG changes the ptp.&lt;br /&gt;
&lt;br /&gt;
In order to make the construction of a field a little more convenient, some very limited type of constructor overloading is incorporated. Both lines could be initialized with either an element of type &amp;lt;tt&amp;gt;ScreenText.new()&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;), i.e. a hash, or it can be initialized with a vector or elements, i.e. with &amp;lt;tt&amp;gt;[ScreenText.new() ScreenText.new() ...]&amp;lt;/tt&amp;gt;. (More on why this is nice to have later.)&lt;br /&gt;
&lt;br /&gt;
 # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
 page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
This part of the code puts this field into the top-left position in the sub page. Each sub page has two columns (&amp;lt;tt&amp;gt;SubPage.left_field[]&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;SubPage.right_field[]&amp;lt;/tt&amp;gt;) of six elements each. The columns are zero indexed.&lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_menu_default.activate();&lt;br /&gt;
This part activates this sup page. Sub page activation is slightly different from base page displaying. The later jumps to the base page and displays whatever sub page is active, &amp;lt;tt&amp;gt;SubPage.activate()&amp;lt;/tt&amp;gt; activates the corresponding sub page in the parent base page and then calls the display function of that page, effectively displaying the sub page.&lt;br /&gt;
&lt;br /&gt;
===Making a more complex SubPage===&lt;br /&gt;
Here just the code:&lt;br /&gt;
  #######################&lt;br /&gt;
  # DETAILS PAGE IDENT&lt;br /&gt;
  #######################&lt;br /&gt;
  #&lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make details for page &amp;quot;~&amp;quot;IDENT&amp;quot;):;&lt;br /&gt;
  &lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_ident_default = SubPage.new(page_ident,name=nil,ptp=&amp;quot;/sub_default&amp;quot;); &lt;br /&gt;
  &lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make fields for page &amp;quot;~&amp;quot;IDENT&amp;quot;):;&lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_model = Field.new(&amp;quot;MODEL&amp;quot;,ScreenText.new(['%s','/instrumentation/cdu/ident/model'],ScreenText[&amp;quot;WHITE&amp;quot;]));&lt;br /&gt;
  var field_engines = Field.new(&amp;quot;ENGINES&amp;quot;,ScreenText.new(['%s','/instrumentation/cdu/ident/engines'],ScreenText[&amp;quot;WHITE&amp;quot;]));&lt;br /&gt;
  var field_navData = Field.new(&amp;quot;NAV DATA&amp;quot;,&amp;quot;----&amp;quot;); &lt;br /&gt;
  var field_navData_active = Field.new(&amp;quot;ACTIVE&amp;quot;,&amp;quot;----&amp;quot;);&lt;br /&gt;
  var field_navData_inactive = Field.new(ScreenText.new(&amp;quot;INACTIVE&amp;quot;,ScreenText[&amp;quot;off&amp;quot;],nil),&amp;quot;----&amp;quot;); &lt;br /&gt;
  var field_dragFf = Field.new(&amp;quot;DRAG/FF&amp;quot;,&amp;quot;+0.0/+0.0&amp;quot;); &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_ident_default.left_field[0]=field_model;&lt;br /&gt;
  page_ident_default.left_field[1]=field_navData;&lt;br /&gt;
  page_ident_default.left_field[5]=page_index.home;&lt;br /&gt;
  page_ident_default.right_field[0]=field_engines;&lt;br /&gt;
  page_ident_default.right_field[1]=field_navData_active;&lt;br /&gt;
  page_ident_default.right_field[2]=field_navData_inactive;&lt;br /&gt;
  page_ident_default.right_field[4]=field_dragFf;&lt;br /&gt;
  page_ident_default.right_field[5]=page_pos_init.home;&lt;br /&gt;
  &lt;br /&gt;
  # place the separators&lt;br /&gt;
  page_ident_default.separators = [11];&lt;br /&gt;
  &lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_ident_default.activate();&lt;br /&gt;
The only new thing here is the use of the more complex version of the screen text constructor and the line&lt;br /&gt;
   page_ident_default.right_field[5]=page_pos_init.home;&lt;br /&gt;
What this does is assigning an auto-generate field of a sub page to a field in another sub page. Thes auto-generated fields can be used to directly activate these sub pages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The Property Tree =&lt;br /&gt;
&lt;br /&gt;
The [[CDU]] also has some properties in the general [[FlightGear]] [[Property Tree]].&lt;br /&gt;
In general it is located in &amp;lt;code&amp;gt;/instrumentation/cdu/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= A Brief History of the Boeing CDU in FlightGear =&lt;br /&gt;
Find some more information on the [[CDU]] at these pages:&lt;br /&gt;
* [[CDU]]&lt;br /&gt;
* [[Howto: Implement a Control Display Unit]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31568</id>
		<title>Nasal Display Matrix Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31568"/>
		<updated>2011-05-09T20:19:01Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
= Internal Representation =&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The utilizes display matrix, showing the text bounding boxes for clarity.]]&lt;br /&gt;
As the screen has a &amp;quot;fixed&amp;quot; resolution, internally the screen is represented as a 14-by-24(-by-2) matrix. The zero-indexed matrix is held in the property tree:&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal double-type variable (although it is only integers).&lt;br /&gt;
&lt;br /&gt;
The style of the char is encoded via a binary key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt;  7&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name (used in the Nasal code for the CDU), which is resolved into a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
the first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;). The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet implemented. [[User:Hcc23|Hcc23]] 14:01, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Nasal Code =&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;.&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields. Several elements can be concattenated in a single line by stacking them in a vector. The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text; or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background.&lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the text element. Here some limited constructor overloading can be used.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  var test_text = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  var test_prop = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
The last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;));&lt;br /&gt;
Furthermore, whenever a property is used in a screen text element on a subpage, the suppage, when displayed, registers listeners on all utilized properties, resulting in updated data on the screen. When the sup page is changed, the listeners are de-registered.&lt;br /&gt;
&lt;br /&gt;
= XML Code =&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== Generating the offset code ==&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=31567</id>
		<title>Howto:Coding a Boeing CDU</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=31567"/>
		<updated>2011-05-09T20:18:40Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* The CDU Screen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
[[User:Gijs|Gijs]] has started an effort to bring a generic Boeing [[CDU]] to [[FlightGear]]. This page tries to describe the coding for this effort.&lt;br /&gt;
&lt;br /&gt;
= The Sources =&lt;br /&gt;
The [[CDU]] is aimed to reside in '''$FGDATA/Aircraft/Instruments-3d/cdu/'''.&lt;br /&gt;
&lt;br /&gt;
'''Graphics''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_Cdu.ac&amp;lt;/tt&amp;gt;: This is a [[AC3D]] file, describing the 3D outline of the CDU model.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_brown.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_grey.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
&lt;br /&gt;
'''XML''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;: This is the main [[XML]] file, providing the direct interface between the 3D model and the code. This file also defines the keypress interactions and the positioning of the text to be displayed in the screen.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt;: An OSGText &amp;quot;model&amp;quot;, used as a baseline for the texts on the screen. Compare to &amp;lt;tt&amp;gt;README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Nasal''':&lt;br /&gt;
The Nasal part is composed of two sections, the framework (which a CDU content coder hopefully would not have to touch) ...&lt;br /&gt;
* &amp;lt;tt&amp;gt;cdu_page_framework.nas&amp;lt;/tt&amp;gt;: This is the main file of the CDU framework. It defines the main ''classes'' used for the CDU.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;: This file contains the Nasal relevant for the dispaly matrix. This code might be useful for other complex screen-based instruments.&lt;br /&gt;
* &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;: This file contains functions which I found useful for my project, but which are totally generic and could be used for other stuff as well.&lt;br /&gt;
* &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;: This file contains a rudimentary timer ''class'' and an example of how to incorporate this with a generic class for an instrument button, allowing the button to call different Nasal scripts, depending on how long it has been pressed. &lt;br /&gt;
* &amp;lt;tt&amp;gt;README&amp;lt;/tt&amp;gt;: Well, a readme.&lt;br /&gt;
... and the actual content implementation&lt;br /&gt;
* &amp;lt;tt&amp;gt;b777_cdu.nas&amp;lt;/tt&amp;gt;: This is the main [[Nasal]] script file to be edited by the ''user'' of the CDU Nasal framework.&lt;br /&gt;
* &amp;lt;tt&amp;gt;b777_cdu_page_XXXXXX.nas&amp;lt;/tt&amp;gt;: The content of the individual pages of the CDU.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' You can find the current version in my git repository at https://gitorious.org/~hcc23/fg/hcc23s-fgdata/trees/cdu-development [[User:Hcc23|Hcc23]] 16:13, 9 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Loading a CDU into an Aircraft ==&lt;br /&gt;
Here is how the CDU is loaded into the Boeing 777-200:&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;777-22ER-set.xml&amp;lt;/tt&amp;gt; the Nasal node is expanded as follows:&lt;br /&gt;
  &amp;lt;instrumentation&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
             &amp;lt;serviceable type=&amp;quot;bool&amp;quot;&amp;gt;true&amp;lt;/serviceable&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
  &amp;lt;instrumentation&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- GENERIC --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!--&lt;br /&gt;
  	      Every CDU needs these files in order to make use of the CDU Framework.&lt;br /&gt;
  	      It should not be necessary to alter these files in order to &amp;quot;just&amp;quot; make&lt;br /&gt;
  	      some CDU pages.&lt;br /&gt;
  	      Think of these files as &amp;quot;header files&amp;quot; or stuff that one uses to &lt;br /&gt;
  	      &amp;quot;inherit&amp;quot; from.&lt;br /&gt;
  	    --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/helping_functions.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/display_matrix.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/timer.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/cdu_page_framework.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- SPECIFIC --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- &lt;br /&gt;
  	      These files here provide the actual content of a CDU and a person &lt;br /&gt;
  	      who wants to create CDU pages needs to change, add, and alter these files.&lt;br /&gt;
  	      Think of these files as where the actuall instantiation happens.&lt;br /&gt;
  	    --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_menu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_index.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_ident.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_pos.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_approach.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_navData.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_navRadio.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_perf.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_thrustLim.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_takeoff.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
Note the difference in the framework files and the actual ''instance'' used for this aircraft. To code pages for the CDU, one would normally not have to mess with the framework files. [[User:Hcc23|Hcc23]]&lt;br /&gt;
&lt;br /&gt;
The 3D model is loaded from within  &amp;lt;tt&amp;gt;$FGDATA/Aircraft/777-200/Models/pedestal.xml&amp;lt;/tt&amp;gt; and the Nasal node is expanded as follows to accomplish that:&lt;br /&gt;
&lt;br /&gt;
     &amp;lt;model&amp;gt;&lt;br /&gt;
        &amp;lt;name&amp;gt;CDU1&amp;lt;/name&amp;gt;&lt;br /&gt;
        &amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/boeing_cdu.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
        &amp;lt;offsets&amp;gt;&lt;br /&gt;
            &amp;lt;x-m&amp;gt;-0.423&amp;lt;/x-m&amp;gt;&lt;br /&gt;
            &amp;lt;y-m&amp;gt;-0.175&amp;lt;/y-m&amp;gt;&lt;br /&gt;
            &amp;lt;z-m&amp;gt;0.559&amp;lt;/z-m&amp;gt;&lt;br /&gt;
            &amp;lt;pitch-deg&amp;gt;-60&amp;lt;/pitch-deg&amp;gt;&lt;br /&gt;
        &amp;lt;/offsets&amp;gt;&lt;br /&gt;
        &amp;lt;overlay&amp;gt;&lt;br /&gt;
            &amp;lt;texture&amp;gt;boeing_brown.png&amp;lt;/texture&amp;gt;&lt;br /&gt;
            &amp;lt;material&amp;gt;&lt;br /&gt;
                &amp;lt;emission&amp;gt;&lt;br /&gt;
                    &amp;lt;red&amp;gt;0.1&amp;lt;/red&amp;gt;&lt;br /&gt;
                    &amp;lt;green&amp;gt;0.1&amp;lt;/green&amp;gt;&lt;br /&gt;
                    &amp;lt;blue&amp;gt;0.1&amp;lt;/blue&amp;gt;&lt;br /&gt;
                &amp;lt;/emission&amp;gt;&lt;br /&gt;
            &amp;lt;/material&amp;gt;&lt;br /&gt;
        &amp;lt;/overlay&amp;gt;&lt;br /&gt;
    &amp;lt;/model&amp;gt;&lt;br /&gt;
    &amp;lt;animation&amp;gt;&lt;br /&gt;
        &amp;lt;type&amp;gt;scale&amp;lt;/type&amp;gt;&lt;br /&gt;
        &amp;lt;object-name&amp;gt;CDU1&amp;lt;/object-name&amp;gt;&lt;br /&gt;
        &amp;lt;x-offset&amp;gt;0.9&amp;lt;/x-offset&amp;gt;&lt;br /&gt;
        &amp;lt;y-offset&amp;gt;0.8&amp;lt;/y-offset&amp;gt;&lt;br /&gt;
        &amp;lt;z-offset&amp;gt;0.9&amp;lt;/z-offset&amp;gt;&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&amp;lt;center&amp;gt;&lt;br /&gt;
            &amp;lt;x-m&amp;gt;-0.423&amp;lt;/x-m&amp;gt;&lt;br /&gt;
            &amp;lt;y-m&amp;gt;-0.175&amp;lt;/y-m&amp;gt;&lt;br /&gt;
            &amp;lt;z-m&amp;gt;0.559&amp;lt;/z-m&amp;gt;&lt;br /&gt;
        &amp;lt;/center&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
    &amp;lt;/animation&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code loads one CDU, the B777-200 has three of them, all loaded in the same way.&lt;br /&gt;
&lt;br /&gt;
== 3D Graphics ==&lt;br /&gt;
The 3D model resides in the file '''&amp;lt;tt&amp;gt;$FGDATA/Models/Cockpit/Instruments-3d/boeing_cdu.ac&amp;lt;/tt&amp;gt;'''. This is a [[AC3D]] file format, but it should be importable by [[Blender]].&lt;br /&gt;
{|&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| [[File:CDU_3D_wireframe.png|thumb|270px|The wireframe of the 3D model and the corresponding coordinate system. ATTENTION: the axis are not right: RED is +X, GREEN is +Z, BLUE is -Y !]]&lt;br /&gt;
| [[File:CDU.png|thumb|270px|The texture of the CDU, a 512x512 PNG bitmap.]]&lt;br /&gt;
| [[File:CDU_3D_textures.png|thumb|270px|The resulting 3D model, after the textures have been added.]]&lt;br /&gt;
|}&lt;br /&gt;
The model also specifies the model internal coordinate system. It is indicated in the pictures through the corresponding axis: X (red), Y (green), and Z (blue). The origin of this coordinate system seems to coincide with the geometric center of the back plane of the [[CDU]], i.e. the YZ-plane is coplanar with the back of the [[CDU]]. The unit of the coordinate system is the SI unit ''Meter''.&lt;br /&gt;
&lt;br /&gt;
The 3D model has has a name assigned to each button. Via XML bindings these can be detected, so when a certain button is clicked, something happens. Currently not all buttons are functional and there is no real way of telling which will do something (other then pressing them and observing the reaction or reading the source code...)&lt;br /&gt;
&lt;br /&gt;
=== The Screen of the CDU ===&lt;br /&gt;
With respect to the model coordinate frame, the screen is the rectangle given by:&lt;br /&gt;
&lt;br /&gt;
  Top edge:   z= 0.111, x=0.004&lt;br /&gt;
  Lower edge: z= 0.019, x=0.004&lt;br /&gt;
  Left edge:  y=-0.051, x=0.004&lt;br /&gt;
  Right edge: y= 0.051, x=0.004&lt;br /&gt;
&lt;br /&gt;
= The Code Framework =&lt;br /&gt;
&lt;br /&gt;
This is a rough overview on the internal framework of the CDU code. A more detailed descriptions can be found at the [[Nasal CDU Framework]] page.&lt;br /&gt;
&lt;br /&gt;
The CDU framework is implemented following some standard object-oriented ideas, completely implemented in Nasal. All variables are instantiated using &amp;lt;tt&amp;gt;var&amp;lt;/tt&amp;gt; so that the global namespace should not be tainted.&lt;br /&gt;
&lt;br /&gt;
The idea for the framework stems from the fact that a CDU is based upon the concept of ''pages'', some of which could occupy several screens. This, in conjunction with the idea of the ''fields'' (stipulated from the screen layout of the CDU) resulted in the following framework:&lt;br /&gt;
  CDU&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | | |-Line&lt;br /&gt;
  | | | |-Line&lt;br /&gt;
  | | | &lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |  |-Line&lt;br /&gt;
  | | |  |-Line&lt;br /&gt;
  | | |&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | | &lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | |&lt;br /&gt;
  | |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  |   |&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-...&lt;br /&gt;
Well, you get the idea....&lt;br /&gt;
&lt;br /&gt;
These four  ''classes'' (BasePage, SubPage, Field, Line) are defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;. The constructors are generally called &amp;lt;tt&amp;gt;.new()&amp;lt;/tt&amp;gt;, all ''members'' are created within the constructors, all ''static'' parts are implemented directly on the hash level.&lt;br /&gt;
&lt;br /&gt;
Beside these four classes the class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;) is used to house the actual text to be printed.&lt;br /&gt;
&lt;br /&gt;
All text is then kept internal to Nasal within the before-mentioned structure. The text is then also kept in the FlightGear property tree so that an interface to osgtext can be established via &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' There is a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable set in the CDU framework. Setting this variable to non-zero enables a bunch of console printouts, implemented via &amp;lt;tt&amp;gt;DEBUG&amp;gt;debug_level?print('....'):;&amp;lt;/tt&amp;gt; Furthermore, when calling a constructor, the parameter &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt; (for path-to-property) can be set, enabling some member variables of the classes to register themselves in the property tree, allowing an easier debugging during runtime. [[User:Hcc23|Hcc23]] 15:20, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
Maybe looking at the actual code is the easiest way of understanding how the framework works. (I also tried to be fairly explicit in my in-code comments, so looking at the sources should actually be helpful, too. [[User:Hcc23|Hcc23]] 15:46, 8 April 2011 (EDT))&lt;br /&gt;
&lt;br /&gt;
As the framework is separate from the ''instanciation'', let's focus on that as that is the part a ''user'' should care mostly about. The relevant file for the Boeing 777-200 is &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Preliminaries===&lt;br /&gt;
  #####################################################&lt;br /&gt;
  # These variables have already been defined in &lt;br /&gt;
  # cdu_page_framework but can (?) be redifined here &lt;br /&gt;
  # for slightly changed versions.&lt;br /&gt;
  #####################################################&lt;br /&gt;
  &lt;br /&gt;
  var ROWS = 14; 	# the number of lines the CDU has&lt;br /&gt;
  var COLS = 24; 	# the number of characters each line can hold&lt;br /&gt;
  var PROP = &amp;quot;/instrumentation/cdu&amp;quot;; 	# generic path to the properties of this CDU&lt;br /&gt;
  var DEBUG = 1; # enable a more verbose &amp;quot;debug&amp;quot; mode, i.e. register all kinds of stuff in the property tree&lt;br /&gt;
  &lt;br /&gt;
  resetDisplayMatrix();&lt;br /&gt;
This essential defines the size of the dispaly matrix, enables the debug printout and clears the display matrix in the property tree.&lt;br /&gt;
(&amp;lt;tt&amp;gt;resetDisplayMatrix();&amp;lt;/tt&amp;gt; fills the complete display matrix with spaces ( ) and also set the style to &amp;lt;tt&amp;gt;&amp;quot;off&amp;quot;&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
===Making the BasePages===&lt;br /&gt;
  # make the pages&lt;br /&gt;
  var page_menu      = BasePage.new(&amp;quot;MENU&amp;quot;,PROP~&amp;quot;/page_menu&amp;quot;); &lt;br /&gt;
  KeyBinding[&amp;quot;MENU&amp;quot;] = func() {page_menu.displayPage(); }; # Note : do NOT forget to wrap displayPage with a function!&lt;br /&gt;
  var page_index     = BasePage.new(&amp;quot;INDEX&amp;quot;,PROP~&amp;quot;/page_index&amp;quot;); &lt;br /&gt;
  var page_ident     = BasePage.new(&amp;quot;IDENT&amp;quot;,PROP~&amp;quot;/page_ident&amp;quot;); &lt;br /&gt;
  var page_pos       = BasePage.new(&amp;quot;POS&amp;quot;,PROP~&amp;quot;/page_pos&amp;quot;); &lt;br /&gt;
  var page_perf      = BasePage.new(&amp;quot;PERF&amp;quot;,PROP~&amp;quot;/page_perf&amp;quot;); &lt;br /&gt;
  var page_thrustLim = BasePage.new(&amp;quot;THRUST LIM&amp;quot;,PROP~&amp;quot;/page_thurstLim&amp;quot;); &lt;br /&gt;
  var page_takeoff   = BasePage.new(&amp;quot;TAKEOFF&amp;quot;,PROP~&amp;quot;/page_takeoff&amp;quot;); &lt;br /&gt;
  var page_approach  = BasePage.new(&amp;quot;APPROACH&amp;quot;,PROP~&amp;quot;/page_approach&amp;quot;); &lt;br /&gt;
  var page_navData   = BasePage.new(&amp;quot;NAV DATA&amp;quot;,PROP~&amp;quot;/page_navData&amp;quot;); &lt;br /&gt;
  var page_maint     = BasePage.new(&amp;quot;MAINT&amp;quot;,PROP~&amp;quot;/page_maint&amp;quot;); &lt;br /&gt;
This section creates the base pages of the CDU. The constructor for base pages is this one:&lt;br /&gt;
  new: func(name,ptp=nil) {...};&lt;br /&gt;
What this essentially does is creating a container to house sub pages. The &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element is used as the title of the page (but this could be overwritten in a sub page), the &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;, if set, registers the base page at that path. (However, if the &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable is set, the the pages are registered by their internal ID in a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; path underneath the CDU.)&lt;br /&gt;
&lt;br /&gt;
When a base page constructor is called, it also creates a ''home''-method. This function can be used to make the corresponding base page the active page, i.e. display that page. As you can see above, the corresponding method of the MENU page is assigned to the related button of the CDU. &amp;lt;tt&amp;gt;KeyBinding&amp;lt;/tt&amp;gt; is defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;, for a list of the available buttons see &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Making a SubPage (and the corresponding Fields)===&lt;br /&gt;
  #######################&lt;br /&gt;
  # DETAILS PAGE MENU&lt;br /&gt;
  #######################&lt;br /&gt;
  #&lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make details for page &amp;quot;~&amp;quot;MENU&amp;quot;):;&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_menu_default = SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,&amp;quot;FMC&amp;quot;,page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
  &lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_menu_default.activate();&lt;br /&gt;
This code section starts to fill in the details of the page MENU. As outlined in the framework, each base page houses sub pages, which in turn house the fields (which hold the actual content). So we need to start by making a sub page:&lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_menu_default = SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
The constructor for a sub page looks like this:&lt;br /&gt;
  new: func(parent_base_page,name=nil,ptp=nil) {...};&lt;br /&gt;
The elements are fairly straight forward:&lt;br /&gt;
* parent_base_page: parent node of this sub page (which is a base page). Note that this is not the name of that page, but the actual page, i.e. put down the name of the variable you made earlier. Here, this is a sub page of &amp;lt;tt&amp;gt;page_menu&amp;lt;/tt&amp;gt;, i.e. the MENU page, which was made earlier.&lt;br /&gt;
* name: similar to the name of a base page, it is used as the title entry of the sub page. If a sub page has a name (which it doesn't need to have), the name of the sub page overwrites the name of the base page, such allowing for slightly different titles on each &amp;quot;screen&amp;quot; of a CDU &amp;quot;page&amp;quot;. Note, however, that the display of the page count is taken care of, i.e. you do not have to put that into the title.&lt;br /&gt;
* ptp: same as with the base page. Also identical, the registration is changed to registration by ID when the DEBUG variable is non-zero.&lt;br /&gt;
&lt;br /&gt;
After a sub page has been made, one needs to make fields to actually hold content:&lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,&amp;quot;FMC&amp;quot;,page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
The first part creates a field, the field constructor is:&lt;br /&gt;
  new: func(label,data,key_action=nil,ptp=nil) {...};&lt;br /&gt;
This constructor is a little more complex than the previous ones:&lt;br /&gt;
* &amp;lt;tt&amp;gt;label&amp;lt;/tt&amp;gt;: the entry for the label line (the top line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;data&amp;lt;/tt&amp;gt;: the entry for data line (the lower line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;: as fields have an line select key associated with them, &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;, a function element, determines what happens when the LSK next to the data line is pressed.&lt;br /&gt;
* &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;: registering the field. As for base and sub pages, a non-zero DEBUG changes the ptp.&lt;br /&gt;
&lt;br /&gt;
In order to make the construction of a field a little more convenient, some very limited type of constructor overloading is incorporated. Both lines could be initialized with either an element of type &amp;lt;tt&amp;gt;ScreenText.new()&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;), i.e. a hash, or it can be initialized with a vector or elements, i.e. with &amp;lt;tt&amp;gt;[ScreenText.new() ScreenText.new() ...]&amp;lt;/tt&amp;gt;. (More on why this is nice to have later.)&lt;br /&gt;
&lt;br /&gt;
 # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
 page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
This part of the code puts this field into the top-left position in the sub page. Each sub page has two columns (&amp;lt;tt&amp;gt;SubPage.left_field[]&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;SubPage.right_field[]&amp;lt;/tt&amp;gt;) of six elements each. The columns are zero indexed.&lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_menu_default.activate();&lt;br /&gt;
This part activates this sup page. Sub page activation is slightly different from base page displaying. The later jumps to the base page and displays whatever sub page is active, &amp;lt;tt&amp;gt;SubPage.activate()&amp;lt;/tt&amp;gt; activates the corresponding sub page in the parent base page and then calls the display function of that page, effectively displaying the sub page.&lt;br /&gt;
&lt;br /&gt;
===Making a more complex SubPage===&lt;br /&gt;
Here just the code:&lt;br /&gt;
  #######################&lt;br /&gt;
  # DETAILS PAGE IDENT&lt;br /&gt;
  #######################&lt;br /&gt;
  #&lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make details for page &amp;quot;~&amp;quot;IDENT&amp;quot;):;&lt;br /&gt;
  &lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_ident_default = SubPage.new(page_ident,name=nil,ptp=&amp;quot;/sub_default&amp;quot;); &lt;br /&gt;
  &lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make fields for page &amp;quot;~&amp;quot;IDENT&amp;quot;):;&lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_model = Field.new(&amp;quot;MODEL&amp;quot;,ScreenText.new(['%s','/instrumentation/cdu/ident/model'],ScreenText[&amp;quot;WHITE&amp;quot;]));&lt;br /&gt;
  var field_engines = Field.new(&amp;quot;ENGINES&amp;quot;,ScreenText.new(['%s','/instrumentation/cdu/ident/engines'],ScreenText[&amp;quot;WHITE&amp;quot;]));&lt;br /&gt;
  var field_navData = Field.new(&amp;quot;NAV DATA&amp;quot;,&amp;quot;----&amp;quot;); &lt;br /&gt;
  var field_navData_active = Field.new(&amp;quot;ACTIVE&amp;quot;,&amp;quot;----&amp;quot;);&lt;br /&gt;
  var field_navData_inactive = Field.new(ScreenText.new(&amp;quot;INACTIVE&amp;quot;,ScreenText[&amp;quot;off&amp;quot;],nil),&amp;quot;----&amp;quot;); &lt;br /&gt;
  var field_dragFf = Field.new(&amp;quot;DRAG/FF&amp;quot;,&amp;quot;+0.0/+0.0&amp;quot;); &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_ident_default.left_field[0]=field_model;&lt;br /&gt;
  page_ident_default.left_field[1]=field_navData;&lt;br /&gt;
  page_ident_default.left_field[5]=page_index.home;&lt;br /&gt;
  page_ident_default.right_field[0]=field_engines;&lt;br /&gt;
  page_ident_default.right_field[1]=field_navData_active;&lt;br /&gt;
  page_ident_default.right_field[2]=field_navData_inactive;&lt;br /&gt;
  page_ident_default.right_field[4]=field_dragFf;&lt;br /&gt;
  page_ident_default.right_field[5]=page_pos_init.home;&lt;br /&gt;
  &lt;br /&gt;
  # place the separators&lt;br /&gt;
  page_ident_default.separators = [11];&lt;br /&gt;
  &lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_ident_default.activate();&lt;br /&gt;
The only new thing here is the use of the more complex version of the screen text constructor and the line&lt;br /&gt;
   page_ident_default.right_field[5]=page_pos_init.home;&lt;br /&gt;
What this does is assigning an auto-generate field of a sub page to a field in another sub page. Thes auto-generated fields can be used to directly activate these sub pages.&lt;br /&gt;
&lt;br /&gt;
= The CDU Screen = &lt;br /&gt;
One of the major problems of the CDU is the representation of the actual screen. According to the Honeywell manual, the CDU utilized by Boeing has a fixed setup which could be captured by a matrix-like approach, i.e. a fixed number of rows and columns (each element holding one character) and an assigned format of that cell.&lt;br /&gt;
&lt;br /&gt;
This setup is replicated within the [[Nasal Display Matrix Framework]], which has been developed for this CDU.&lt;br /&gt;
&lt;br /&gt;
== Details of the (LCD) Screen ==&lt;br /&gt;
The LCD has '''14 lines''' with a total of '''24 characters per line'''. The page format is formatted as follows:&lt;br /&gt;
&lt;br /&gt;
* Title Field: The top line of the display area. Id identifies the subject or title of the data displayed on the page in view. It also identifies page number and the number of pages in series, e.g., &amp;lt;tt&amp;gt;1/2&amp;lt;/tt&amp;gt; identifies a page as the first in a series of two pages.&lt;br /&gt;
* Left Field: 6 pairs of lines, 11 characters per line. It extends from the left side of the screen to the center. The pilot has access to one line of each pair through a LSK (Line-Select Key) on the left side of the CDU. A line pair is made up of a label and a data line.&lt;br /&gt;
* Right Field: This field is similar to the left field, extending from the center of the screen to the right side. Pilot access is available by a LSK on the right side. &lt;br /&gt;
* Scratchpad: The bottom line of the display screen. This line displays alphanumeric data or messages. Data can be entered with the alphanumeric keys or the LSK, or by the FMC. Scratchpad entry cannot, normally, be made with a FMC message in the scratchpad. Scratchpad entries are independent of page selection, and remain until cleared even when page changes occur. Scratchpad data entries and erases affect only the associated CDU. Messages can appear and be erased on both CDUs simultaneously.&lt;br /&gt;
&lt;br /&gt;
For more details on the implementation of the display matrix, read the page on the [[Nasal Display Matrix Framework]].&lt;br /&gt;
&lt;br /&gt;
= The Property Tree =&lt;br /&gt;
&lt;br /&gt;
The [[CDU]] also has some properties in the general [[FlightGear]] [[Property Tree]].&lt;br /&gt;
In general it is located in &amp;lt;code&amp;gt;/instrumentation/cdu/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= A Brief History of the Boeing CDU in FlightGear =&lt;br /&gt;
Find some more information on the [[CDU]] at these pages:&lt;br /&gt;
* [[CDU]]&lt;br /&gt;
* [[Howto: Implement a Control Display Unit]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31566</id>
		<title>Nasal Display Matrix Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_Display_Matrix_Framework&amp;diff=31566"/>
		<updated>2011-05-09T20:17:24Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: Created page by exproting stuff from a too long page about the CDU&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Internal Representation =&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The utilizes display matrix, showing the text bounding boxes for clarity.]]&lt;br /&gt;
As the screen has a &amp;quot;fixed&amp;quot; resolution, internally the screen is represented as a 14-by-24(-by-2) matrix. The zero-indexed matrix is held in the property tree:&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal double-type variable (although it is only integers).&lt;br /&gt;
&lt;br /&gt;
The style of the char is encoded via a binary key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt;  7&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name (used in the Nasal code for the CDU), which is resolved into a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
the first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;). The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet implemented. [[User:Hcc23|Hcc23]] 14:01, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Nasal Code =&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;.&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields. Several elements can be concattenated in a single line by stacking them in a vector. The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text; or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background.&lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the text element. Here some limited constructor overloading can be used.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  var test_text = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  var test_prop = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
The last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;));&lt;br /&gt;
Furthermore, whenever a property is used in a screen text element on a subpage, the suppage, when displayed, registers listeners on all utilized properties, resulting in updated data on the screen. When the sup page is changed, the listeners are de-registered.&lt;br /&gt;
&lt;br /&gt;
= XML Code =&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== Generating the offset code ==&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=31565</id>
		<title>Howto:Coding a Boeing CDU</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=31565"/>
		<updated>2011-05-09T20:13:13Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* The Sources */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
[[User:Gijs|Gijs]] has started an effort to bring a generic Boeing [[CDU]] to [[FlightGear]]. This page tries to describe the coding for this effort.&lt;br /&gt;
&lt;br /&gt;
= The Sources =&lt;br /&gt;
The [[CDU]] is aimed to reside in '''$FGDATA/Aircraft/Instruments-3d/cdu/'''.&lt;br /&gt;
&lt;br /&gt;
'''Graphics''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_Cdu.ac&amp;lt;/tt&amp;gt;: This is a [[AC3D]] file, describing the 3D outline of the CDU model.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_brown.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_grey.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
&lt;br /&gt;
'''XML''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;: This is the main [[XML]] file, providing the direct interface between the 3D model and the code. This file also defines the keypress interactions and the positioning of the text to be displayed in the screen.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix_text.xml&amp;lt;/tt&amp;gt;: An OSGText &amp;quot;model&amp;quot;, used as a baseline for the texts on the screen. Compare to &amp;lt;tt&amp;gt;README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Nasal''':&lt;br /&gt;
The Nasal part is composed of two sections, the framework (which a CDU content coder hopefully would not have to touch) ...&lt;br /&gt;
* &amp;lt;tt&amp;gt;cdu_page_framework.nas&amp;lt;/tt&amp;gt;: This is the main file of the CDU framework. It defines the main ''classes'' used for the CDU.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;: This file contains the Nasal relevant for the dispaly matrix. This code might be useful for other complex screen-based instruments.&lt;br /&gt;
* &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;: This file contains functions which I found useful for my project, but which are totally generic and could be used for other stuff as well.&lt;br /&gt;
* &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;: This file contains a rudimentary timer ''class'' and an example of how to incorporate this with a generic class for an instrument button, allowing the button to call different Nasal scripts, depending on how long it has been pressed. &lt;br /&gt;
* &amp;lt;tt&amp;gt;README&amp;lt;/tt&amp;gt;: Well, a readme.&lt;br /&gt;
... and the actual content implementation&lt;br /&gt;
* &amp;lt;tt&amp;gt;b777_cdu.nas&amp;lt;/tt&amp;gt;: This is the main [[Nasal]] script file to be edited by the ''user'' of the CDU Nasal framework.&lt;br /&gt;
* &amp;lt;tt&amp;gt;b777_cdu_page_XXXXXX.nas&amp;lt;/tt&amp;gt;: The content of the individual pages of the CDU.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' You can find the current version in my git repository at https://gitorious.org/~hcc23/fg/hcc23s-fgdata/trees/cdu-development [[User:Hcc23|Hcc23]] 16:13, 9 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Loading a CDU into an Aircraft ==&lt;br /&gt;
Here is how the CDU is loaded into the Boeing 777-200:&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;777-22ER-set.xml&amp;lt;/tt&amp;gt; the Nasal node is expanded as follows:&lt;br /&gt;
  &amp;lt;instrumentation&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
             &amp;lt;serviceable type=&amp;quot;bool&amp;quot;&amp;gt;true&amp;lt;/serviceable&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
  &amp;lt;instrumentation&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- GENERIC --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!--&lt;br /&gt;
  	      Every CDU needs these files in order to make use of the CDU Framework.&lt;br /&gt;
  	      It should not be necessary to alter these files in order to &amp;quot;just&amp;quot; make&lt;br /&gt;
  	      some CDU pages.&lt;br /&gt;
  	      Think of these files as &amp;quot;header files&amp;quot; or stuff that one uses to &lt;br /&gt;
  	      &amp;quot;inherit&amp;quot; from.&lt;br /&gt;
  	    --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/helping_functions.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/display_matrix.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/timer.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/framework/cdu_page_framework.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- SPECIFIC --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- &lt;br /&gt;
  	      These files here provide the actual content of a CDU and a person &lt;br /&gt;
  	      who wants to create CDU pages needs to change, add, and alter these files.&lt;br /&gt;
  	      Think of these files as where the actuall instantiation happens.&lt;br /&gt;
  	    --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_menu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_index.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_ident.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_pos.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_approach.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_navData.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_navRadio.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_perf.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_thrustLim.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
  	    &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/Nasal/b777/b777_cdu_page_takeoff.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
Note the difference in the framework files and the actual ''instance'' used for this aircraft. To code pages for the CDU, one would normally not have to mess with the framework files. [[User:Hcc23|Hcc23]]&lt;br /&gt;
&lt;br /&gt;
The 3D model is loaded from within  &amp;lt;tt&amp;gt;$FGDATA/Aircraft/777-200/Models/pedestal.xml&amp;lt;/tt&amp;gt; and the Nasal node is expanded as follows to accomplish that:&lt;br /&gt;
&lt;br /&gt;
     &amp;lt;model&amp;gt;&lt;br /&gt;
        &amp;lt;name&amp;gt;CDU1&amp;lt;/name&amp;gt;&lt;br /&gt;
        &amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/boeing_cdu.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
        &amp;lt;offsets&amp;gt;&lt;br /&gt;
            &amp;lt;x-m&amp;gt;-0.423&amp;lt;/x-m&amp;gt;&lt;br /&gt;
            &amp;lt;y-m&amp;gt;-0.175&amp;lt;/y-m&amp;gt;&lt;br /&gt;
            &amp;lt;z-m&amp;gt;0.559&amp;lt;/z-m&amp;gt;&lt;br /&gt;
            &amp;lt;pitch-deg&amp;gt;-60&amp;lt;/pitch-deg&amp;gt;&lt;br /&gt;
        &amp;lt;/offsets&amp;gt;&lt;br /&gt;
        &amp;lt;overlay&amp;gt;&lt;br /&gt;
            &amp;lt;texture&amp;gt;boeing_brown.png&amp;lt;/texture&amp;gt;&lt;br /&gt;
            &amp;lt;material&amp;gt;&lt;br /&gt;
                &amp;lt;emission&amp;gt;&lt;br /&gt;
                    &amp;lt;red&amp;gt;0.1&amp;lt;/red&amp;gt;&lt;br /&gt;
                    &amp;lt;green&amp;gt;0.1&amp;lt;/green&amp;gt;&lt;br /&gt;
                    &amp;lt;blue&amp;gt;0.1&amp;lt;/blue&amp;gt;&lt;br /&gt;
                &amp;lt;/emission&amp;gt;&lt;br /&gt;
            &amp;lt;/material&amp;gt;&lt;br /&gt;
        &amp;lt;/overlay&amp;gt;&lt;br /&gt;
    &amp;lt;/model&amp;gt;&lt;br /&gt;
    &amp;lt;animation&amp;gt;&lt;br /&gt;
        &amp;lt;type&amp;gt;scale&amp;lt;/type&amp;gt;&lt;br /&gt;
        &amp;lt;object-name&amp;gt;CDU1&amp;lt;/object-name&amp;gt;&lt;br /&gt;
        &amp;lt;x-offset&amp;gt;0.9&amp;lt;/x-offset&amp;gt;&lt;br /&gt;
        &amp;lt;y-offset&amp;gt;0.8&amp;lt;/y-offset&amp;gt;&lt;br /&gt;
        &amp;lt;z-offset&amp;gt;0.9&amp;lt;/z-offset&amp;gt;&lt;br /&gt;
        &amp;lt;nowiki&amp;gt;&amp;lt;center&amp;gt;&lt;br /&gt;
            &amp;lt;x-m&amp;gt;-0.423&amp;lt;/x-m&amp;gt;&lt;br /&gt;
            &amp;lt;y-m&amp;gt;-0.175&amp;lt;/y-m&amp;gt;&lt;br /&gt;
            &amp;lt;z-m&amp;gt;0.559&amp;lt;/z-m&amp;gt;&lt;br /&gt;
        &amp;lt;/center&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
    &amp;lt;/animation&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that this code loads one CDU, the B777-200 has three of them, all loaded in the same way.&lt;br /&gt;
&lt;br /&gt;
== 3D Graphics ==&lt;br /&gt;
The 3D model resides in the file '''&amp;lt;tt&amp;gt;$FGDATA/Models/Cockpit/Instruments-3d/boeing_cdu.ac&amp;lt;/tt&amp;gt;'''. This is a [[AC3D]] file format, but it should be importable by [[Blender]].&lt;br /&gt;
{|&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| [[File:CDU_3D_wireframe.png|thumb|270px|The wireframe of the 3D model and the corresponding coordinate system. ATTENTION: the axis are not right: RED is +X, GREEN is +Z, BLUE is -Y !]]&lt;br /&gt;
| [[File:CDU.png|thumb|270px|The texture of the CDU, a 512x512 PNG bitmap.]]&lt;br /&gt;
| [[File:CDU_3D_textures.png|thumb|270px|The resulting 3D model, after the textures have been added.]]&lt;br /&gt;
|}&lt;br /&gt;
The model also specifies the model internal coordinate system. It is indicated in the pictures through the corresponding axis: X (red), Y (green), and Z (blue). The origin of this coordinate system seems to coincide with the geometric center of the back plane of the [[CDU]], i.e. the YZ-plane is coplanar with the back of the [[CDU]]. The unit of the coordinate system is the SI unit ''Meter''.&lt;br /&gt;
&lt;br /&gt;
The 3D model has has a name assigned to each button. Via XML bindings these can be detected, so when a certain button is clicked, something happens. Currently not all buttons are functional and there is no real way of telling which will do something (other then pressing them and observing the reaction or reading the source code...)&lt;br /&gt;
&lt;br /&gt;
=== The Screen of the CDU ===&lt;br /&gt;
With respect to the model coordinate frame, the screen is the rectangle given by:&lt;br /&gt;
&lt;br /&gt;
  Top edge:   z= 0.111, x=0.004&lt;br /&gt;
  Lower edge: z= 0.019, x=0.004&lt;br /&gt;
  Left edge:  y=-0.051, x=0.004&lt;br /&gt;
  Right edge: y= 0.051, x=0.004&lt;br /&gt;
&lt;br /&gt;
= The Code Framework =&lt;br /&gt;
&lt;br /&gt;
This is a rough overview on the internal framework of the CDU code. A more detailed descriptions can be found at the [[Nasal CDU Framework]] page.&lt;br /&gt;
&lt;br /&gt;
The CDU framework is implemented following some standard object-oriented ideas, completely implemented in Nasal. All variables are instantiated using &amp;lt;tt&amp;gt;var&amp;lt;/tt&amp;gt; so that the global namespace should not be tainted.&lt;br /&gt;
&lt;br /&gt;
The idea for the framework stems from the fact that a CDU is based upon the concept of ''pages'', some of which could occupy several screens. This, in conjunction with the idea of the ''fields'' (stipulated from the screen layout of the CDU) resulted in the following framework:&lt;br /&gt;
  CDU&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | | |-Line&lt;br /&gt;
  | | | |-Line&lt;br /&gt;
  | | | &lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |  |-Line&lt;br /&gt;
  | | |  |-Line&lt;br /&gt;
  | | |&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | | &lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | |&lt;br /&gt;
  | |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  |   |&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-...&lt;br /&gt;
Well, you get the idea....&lt;br /&gt;
&lt;br /&gt;
These four  ''classes'' (BasePage, SubPage, Field, Line) are defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;. The constructors are generally called &amp;lt;tt&amp;gt;.new()&amp;lt;/tt&amp;gt;, all ''members'' are created within the constructors, all ''static'' parts are implemented directly on the hash level.&lt;br /&gt;
&lt;br /&gt;
Beside these four classes the class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;) is used to house the actual text to be printed.&lt;br /&gt;
&lt;br /&gt;
All text is then kept internal to Nasal within the before-mentioned structure. The text is then also kept in the FlightGear property tree so that an interface to osgtext can be established via &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' There is a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable set in the CDU framework. Setting this variable to non-zero enables a bunch of console printouts, implemented via &amp;lt;tt&amp;gt;DEBUG&amp;gt;debug_level?print('....'):;&amp;lt;/tt&amp;gt; Furthermore, when calling a constructor, the parameter &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt; (for path-to-property) can be set, enabling some member variables of the classes to register themselves in the property tree, allowing an easier debugging during runtime. [[User:Hcc23|Hcc23]] 15:20, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
Maybe looking at the actual code is the easiest way of understanding how the framework works. (I also tried to be fairly explicit in my in-code comments, so looking at the sources should actually be helpful, too. [[User:Hcc23|Hcc23]] 15:46, 8 April 2011 (EDT))&lt;br /&gt;
&lt;br /&gt;
As the framework is separate from the ''instanciation'', let's focus on that as that is the part a ''user'' should care mostly about. The relevant file for the Boeing 777-200 is &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Preliminaries===&lt;br /&gt;
  #####################################################&lt;br /&gt;
  # These variables have already been defined in &lt;br /&gt;
  # cdu_page_framework but can (?) be redifined here &lt;br /&gt;
  # for slightly changed versions.&lt;br /&gt;
  #####################################################&lt;br /&gt;
  &lt;br /&gt;
  var ROWS = 14; 	# the number of lines the CDU has&lt;br /&gt;
  var COLS = 24; 	# the number of characters each line can hold&lt;br /&gt;
  var PROP = &amp;quot;/instrumentation/cdu&amp;quot;; 	# generic path to the properties of this CDU&lt;br /&gt;
  var DEBUG = 1; # enable a more verbose &amp;quot;debug&amp;quot; mode, i.e. register all kinds of stuff in the property tree&lt;br /&gt;
  &lt;br /&gt;
  resetDisplayMatrix();&lt;br /&gt;
This essential defines the size of the dispaly matrix, enables the debug printout and clears the display matrix in the property tree.&lt;br /&gt;
(&amp;lt;tt&amp;gt;resetDisplayMatrix();&amp;lt;/tt&amp;gt; fills the complete display matrix with spaces ( ) and also set the style to &amp;lt;tt&amp;gt;&amp;quot;off&amp;quot;&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
===Making the BasePages===&lt;br /&gt;
  # make the pages&lt;br /&gt;
  var page_menu      = BasePage.new(&amp;quot;MENU&amp;quot;,PROP~&amp;quot;/page_menu&amp;quot;); &lt;br /&gt;
  KeyBinding[&amp;quot;MENU&amp;quot;] = func() {page_menu.displayPage(); }; # Note : do NOT forget to wrap displayPage with a function!&lt;br /&gt;
  var page_index     = BasePage.new(&amp;quot;INDEX&amp;quot;,PROP~&amp;quot;/page_index&amp;quot;); &lt;br /&gt;
  var page_ident     = BasePage.new(&amp;quot;IDENT&amp;quot;,PROP~&amp;quot;/page_ident&amp;quot;); &lt;br /&gt;
  var page_pos       = BasePage.new(&amp;quot;POS&amp;quot;,PROP~&amp;quot;/page_pos&amp;quot;); &lt;br /&gt;
  var page_perf      = BasePage.new(&amp;quot;PERF&amp;quot;,PROP~&amp;quot;/page_perf&amp;quot;); &lt;br /&gt;
  var page_thrustLim = BasePage.new(&amp;quot;THRUST LIM&amp;quot;,PROP~&amp;quot;/page_thurstLim&amp;quot;); &lt;br /&gt;
  var page_takeoff   = BasePage.new(&amp;quot;TAKEOFF&amp;quot;,PROP~&amp;quot;/page_takeoff&amp;quot;); &lt;br /&gt;
  var page_approach  = BasePage.new(&amp;quot;APPROACH&amp;quot;,PROP~&amp;quot;/page_approach&amp;quot;); &lt;br /&gt;
  var page_navData   = BasePage.new(&amp;quot;NAV DATA&amp;quot;,PROP~&amp;quot;/page_navData&amp;quot;); &lt;br /&gt;
  var page_maint     = BasePage.new(&amp;quot;MAINT&amp;quot;,PROP~&amp;quot;/page_maint&amp;quot;); &lt;br /&gt;
This section creates the base pages of the CDU. The constructor for base pages is this one:&lt;br /&gt;
  new: func(name,ptp=nil) {...};&lt;br /&gt;
What this essentially does is creating a container to house sub pages. The &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element is used as the title of the page (but this could be overwritten in a sub page), the &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;, if set, registers the base page at that path. (However, if the &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable is set, the the pages are registered by their internal ID in a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; path underneath the CDU.)&lt;br /&gt;
&lt;br /&gt;
When a base page constructor is called, it also creates a ''home''-method. This function can be used to make the corresponding base page the active page, i.e. display that page. As you can see above, the corresponding method of the MENU page is assigned to the related button of the CDU. &amp;lt;tt&amp;gt;KeyBinding&amp;lt;/tt&amp;gt; is defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;, for a list of the available buttons see &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Making a SubPage (and the corresponding Fields)===&lt;br /&gt;
  #######################&lt;br /&gt;
  # DETAILS PAGE MENU&lt;br /&gt;
  #######################&lt;br /&gt;
  #&lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make details for page &amp;quot;~&amp;quot;MENU&amp;quot;):;&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_menu_default = SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,&amp;quot;FMC&amp;quot;,page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
  &lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_menu_default.activate();&lt;br /&gt;
This code section starts to fill in the details of the page MENU. As outlined in the framework, each base page houses sub pages, which in turn house the fields (which hold the actual content). So we need to start by making a sub page:&lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_menu_default = SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
The constructor for a sub page looks like this:&lt;br /&gt;
  new: func(parent_base_page,name=nil,ptp=nil) {...};&lt;br /&gt;
The elements are fairly straight forward:&lt;br /&gt;
* parent_base_page: parent node of this sub page (which is a base page). Note that this is not the name of that page, but the actual page, i.e. put down the name of the variable you made earlier. Here, this is a sub page of &amp;lt;tt&amp;gt;page_menu&amp;lt;/tt&amp;gt;, i.e. the MENU page, which was made earlier.&lt;br /&gt;
* name: similar to the name of a base page, it is used as the title entry of the sub page. If a sub page has a name (which it doesn't need to have), the name of the sub page overwrites the name of the base page, such allowing for slightly different titles on each &amp;quot;screen&amp;quot; of a CDU &amp;quot;page&amp;quot;. Note, however, that the display of the page count is taken care of, i.e. you do not have to put that into the title.&lt;br /&gt;
* ptp: same as with the base page. Also identical, the registration is changed to registration by ID when the DEBUG variable is non-zero.&lt;br /&gt;
&lt;br /&gt;
After a sub page has been made, one needs to make fields to actually hold content:&lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,&amp;quot;FMC&amp;quot;,page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
The first part creates a field, the field constructor is:&lt;br /&gt;
  new: func(label,data,key_action=nil,ptp=nil) {...};&lt;br /&gt;
This constructor is a little more complex than the previous ones:&lt;br /&gt;
* &amp;lt;tt&amp;gt;label&amp;lt;/tt&amp;gt;: the entry for the label line (the top line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;data&amp;lt;/tt&amp;gt;: the entry for data line (the lower line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;: as fields have an line select key associated with them, &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;, a function element, determines what happens when the LSK next to the data line is pressed.&lt;br /&gt;
* &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;: registering the field. As for base and sub pages, a non-zero DEBUG changes the ptp.&lt;br /&gt;
&lt;br /&gt;
In order to make the construction of a field a little more convenient, some very limited type of constructor overloading is incorporated. Both lines could be initialized with either an element of type &amp;lt;tt&amp;gt;ScreenText.new()&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;), i.e. a hash, or it can be initialized with a vector or elements, i.e. with &amp;lt;tt&amp;gt;[ScreenText.new() ScreenText.new() ...]&amp;lt;/tt&amp;gt;. (More on why this is nice to have later.)&lt;br /&gt;
&lt;br /&gt;
 # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
 page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
This part of the code puts this field into the top-left position in the sub page. Each sub page has two columns (&amp;lt;tt&amp;gt;SubPage.left_field[]&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;SubPage.right_field[]&amp;lt;/tt&amp;gt;) of six elements each. The columns are zero indexed.&lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_menu_default.activate();&lt;br /&gt;
This part activates this sup page. Sub page activation is slightly different from base page displaying. The later jumps to the base page and displays whatever sub page is active, &amp;lt;tt&amp;gt;SubPage.activate()&amp;lt;/tt&amp;gt; activates the corresponding sub page in the parent base page and then calls the display function of that page, effectively displaying the sub page.&lt;br /&gt;
&lt;br /&gt;
===Making a more complex SubPage===&lt;br /&gt;
Here just the code:&lt;br /&gt;
  #######################&lt;br /&gt;
  # DETAILS PAGE IDENT&lt;br /&gt;
  #######################&lt;br /&gt;
  #&lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make details for page &amp;quot;~&amp;quot;IDENT&amp;quot;):;&lt;br /&gt;
  &lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_ident_default = SubPage.new(page_ident,name=nil,ptp=&amp;quot;/sub_default&amp;quot;); &lt;br /&gt;
  &lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make fields for page &amp;quot;~&amp;quot;IDENT&amp;quot;):;&lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_model = Field.new(&amp;quot;MODEL&amp;quot;,ScreenText.new(['%s','/instrumentation/cdu/ident/model'],ScreenText[&amp;quot;WHITE&amp;quot;]));&lt;br /&gt;
  var field_engines = Field.new(&amp;quot;ENGINES&amp;quot;,ScreenText.new(['%s','/instrumentation/cdu/ident/engines'],ScreenText[&amp;quot;WHITE&amp;quot;]));&lt;br /&gt;
  var field_navData = Field.new(&amp;quot;NAV DATA&amp;quot;,&amp;quot;----&amp;quot;); &lt;br /&gt;
  var field_navData_active = Field.new(&amp;quot;ACTIVE&amp;quot;,&amp;quot;----&amp;quot;);&lt;br /&gt;
  var field_navData_inactive = Field.new(ScreenText.new(&amp;quot;INACTIVE&amp;quot;,ScreenText[&amp;quot;off&amp;quot;],nil),&amp;quot;----&amp;quot;); &lt;br /&gt;
  var field_dragFf = Field.new(&amp;quot;DRAG/FF&amp;quot;,&amp;quot;+0.0/+0.0&amp;quot;); &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_ident_default.left_field[0]=field_model;&lt;br /&gt;
  page_ident_default.left_field[1]=field_navData;&lt;br /&gt;
  page_ident_default.left_field[5]=page_index.home;&lt;br /&gt;
  page_ident_default.right_field[0]=field_engines;&lt;br /&gt;
  page_ident_default.right_field[1]=field_navData_active;&lt;br /&gt;
  page_ident_default.right_field[2]=field_navData_inactive;&lt;br /&gt;
  page_ident_default.right_field[4]=field_dragFf;&lt;br /&gt;
  page_ident_default.right_field[5]=page_pos_init.home;&lt;br /&gt;
  &lt;br /&gt;
  # place the separators&lt;br /&gt;
  page_ident_default.separators = [11];&lt;br /&gt;
  &lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_ident_default.activate();&lt;br /&gt;
The only new thing here is the use of the more complex version of the screen text constructor and the line&lt;br /&gt;
   page_ident_default.right_field[5]=page_pos_init.home;&lt;br /&gt;
What this does is assigning an auto-generate field of a sub page to a field in another sub page. Thes auto-generated fields can be used to directly activate these sub pages.&lt;br /&gt;
&lt;br /&gt;
= The CDU Screen = &lt;br /&gt;
One of the major problems of the CDU is the representation of the actual screen. According to the Honeywell manual, the CDU utilized by Boeing has a fixed setup.&lt;br /&gt;
&lt;br /&gt;
== Details of the (LCD) Screen ==&lt;br /&gt;
The LCD has '''14 lines''' with a total of '''24 characters per line'''. The page format is formatted as follows:&lt;br /&gt;
&lt;br /&gt;
* Title Field: The top line of the display area. Id identifies the subject or title of the data displayed on the page in view. It also identifies page number and the number of pages in series, e.g., &amp;lt;tt&amp;gt;1/2&amp;lt;/tt&amp;gt; identifies a page as the first in a series of two pages.&lt;br /&gt;
* Left Field: 6 pairs of lines, 11 characters per line. It extends from the left side of the screen to the center. The pilot has access to one line of each pair through a LSK (Line-Select Key) on the left side of the CDU. A line pair is made up of a label and a data line.&lt;br /&gt;
* Right Field: This field is similar to the left field, extending from the center of the screen to the right side. Pilot access is available by a LSK on the right side. &lt;br /&gt;
* Scratchpad: The bottom line of the display screen. This line displays alphanumeric data or messages. Data can be entered with the alphanumeric keys or the LSK, or by the FMC. Scratchpad entry cannot, normally, be made with a FMC message in the scratchpad. Scratchpad entries are independent of page selection, and remain until cleared even when page changes occur. Scratchpad data entries and erases affect only the associated CDU. Messages can appear and be erased on both CDUs simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Internal Representation ==&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The utilizes display matrix, showing the text bounding boxes for clarity.]]&lt;br /&gt;
As the screen has a &amp;quot;fixed&amp;quot; resolution, internally the screen is represented as a 14-by-24(-by-2) matrix. The zero-indexed matrix is held in the property tree:&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal double-type variable (although it is only integers).&lt;br /&gt;
&lt;br /&gt;
The style of the char is encoded via a binary key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt;  7&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name (used in the Nasal code for the CDU), which is resolved into a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
the first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;). The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet implemented. [[User:Hcc23|Hcc23]] 14:01, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Nasal Code ==&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;.&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields. Several elements can be concattenated in a single line by stacking them in a vector. The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text; or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background.&lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the text element. Here some limited constructor overloading can be used.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  var test_text = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  var test_prop = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
The last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;));&lt;br /&gt;
Furthermore, whenever a property is used in a screen text element on a subpage, the suppage, when displayed, registers listeners on all utilized properties, resulting in updated data on the screen. When the sup page is changed, the listeners are de-registered.&lt;br /&gt;
&lt;br /&gt;
== XML Code ==&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== Generating the offset code ===&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= The Property Tree =&lt;br /&gt;
&lt;br /&gt;
The [[CDU]] also has some properties in the general [[FlightGear]] [[Property Tree]].&lt;br /&gt;
In general it is located in &amp;lt;code&amp;gt;/instrumentation/cdu/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= A Brief History of the Boeing CDU in FlightGear =&lt;br /&gt;
Find some more information on the [[CDU]] at these pages:&lt;br /&gt;
* [[CDU]]&lt;br /&gt;
* [[Howto: Implement a Control Display Unit]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31563</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31563"/>
		<updated>2011-05-09T19:09:53Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
These are the core classes in the CDU framework. The documentation should show a brief comment on what each variable or function is intended to do, particularly the ones that are important for the '''creation''' of an actual, content-filled CDU page.&lt;br /&gt;
&lt;br /&gt;
Although Nasal as such has no support for this, the internal stuff in a class is sectioned in three categories, borrowing language from &amp;lt;tt&amp;gt;C++&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Static:''' Stuff in this section is mainly identified by being made directly as part of the &amp;lt;tt&amp;gt;hash&amp;lt;/tt&amp;gt; (as opposed to being ''tagged on'' by the the &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; constructor. Elements in here also follow a ''camelCase'' type of notation, whereas ''members'' use an ''underscore_naming_convetion''. Please note that although meant to be comparable to statics, in hindsight a lot of them would be better placed in the member section Public...&lt;br /&gt;
&lt;br /&gt;
* '''Public:''' Elements in here are created from inside the &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; constructor and follow an ''underscore_naming_convetion''. In a perfect world these would only be accessing functions, as exposing variables is always prone for trouble when the time for a redesign comes... Elements in here should be the only ones used in the creation of a page - in a perfect world.&lt;br /&gt;
&lt;br /&gt;
* '''Private:''' Elements in here are created from inside the &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; constructor and follow an ''underscore_naming_convetion''. Although readable by everybody, access to these elements should be limited to functions in the static and public parts of the classes code. Particularly no page creation (user) code should need to access this information.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' I know that I violate these rules. Yes. But I have rewritten the framework to often to (at this point) care much about it - particularly as it seems to be working. Please, feel free to correct the Nasal code I have written (which might involve the pain of revisiting the page creation sections... Sorry for that.) [[User:Hcc23|Hcc23]] 14:45, 9 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	formatOutput(input_data),&lt;br /&gt;
    func 	getScreenTextVector(),&lt;br /&gt;
    func 	new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.used_properties,&lt;br /&gt;
    vector 	me.line_data,&lt;br /&gt;
    scalar 	me.line_string_length,&lt;br /&gt;
    func 	me.enable(),&lt;br /&gt;
    func 	me.disable(),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
A field holds two lines, the label and the data line, as well as information about what the associated line select key does.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Field = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	new(label,data,key_action=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
  &lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.used_properties(),&lt;br /&gt;
    func 	me.lsk_binding(),&lt;br /&gt;
    func 	me.enable_lsk(),&lt;br /&gt;
    func 	me.disable_lsk(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    (Line)	me.label_line,	&lt;br /&gt;
    (Line) 	me.data_line,&lt;br /&gt;
    scalar 	me.lsk_active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
A SubPage is actually the main element in the CDU framework. It holds the content via its fields and manages the updating of the CDU screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var SubPage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    (Field) 	blankField,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	updateField(field, side, lsk_index),	&lt;br /&gt;
    func 	displayFields(field_vector, side),&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	new(parent_base_page,name=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar      me.separator,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    func 	me.register_field(field_pos,field),&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.parent,&lt;br /&gt;
    scalar      me.title,&lt;br /&gt;
    scalar      me.status,&lt;br /&gt;
    vector 	me.left_field,&lt;br /&gt;
    vector      me.right_field,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
A BasePage is exactly that: a base to hold sub pages. A base page most closely represents the concept of a '''page''' in a CDU.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var BasePage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	regiserInPropTree(path)&lt;br /&gt;
    func 	new(name,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.active_sub_page_id,&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    vector 	me.sub_pages,&lt;br /&gt;
    scalar 	me.title,&lt;br /&gt;
    scalar 	me.status,&lt;br /&gt;
    &lt;br /&gt;
  };  &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
The CDU is the main class for the instrument. Each simulated CDU should have one and only one CDU instance associated to it. This is intended to support multiple CDUs showing different content in the future.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var CDU = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    func 	M_ERROR(message_string),&lt;br /&gt;
    func 	M_WARNING(message_string),&lt;br /&gt;
    func 	M_NOTE(message_string),&lt;br /&gt;
    func 	M_HINT(message_string),&lt;br /&gt;
  &lt;br /&gt;
    func 	updateDisplay(),&lt;br /&gt;
    scalar 	activeBasePageID,&lt;br /&gt;
  &lt;br /&gt;
    (ScratchPad) 		scratchPad,&lt;br /&gt;
    (Timer) 			timer,&lt;br /&gt;
    (ListenerCollection) 	listOfListeners,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Additional Infrastructure =&lt;br /&gt;
The previous section was more concerned with the conceptually necessary pieces for a/the CDU. This section introduces the other elements the framework introduces in order to code a functional CDU.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ScratchPad ==&lt;br /&gt;
&lt;br /&gt;
The ScratchPad is the input/output line in the CDU(s). The scratch pas as such is kind of different from the rest of the CDU(s) as the scratch pad messages are truly static, i.e. they happen to be displayed on all CDUs in the cockpit, no matter what the individual CDU is otherwise showing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ScratchPad = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	messages,&lt;br /&gt;
    scalar 	deleteString, # &amp;quot;DELETE&amp;quot;~&amp;quot;&amp;quot;&lt;br /&gt;
    func 	displayScratchPad(),&lt;br /&gt;
    func 	new(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.input_string,&lt;br /&gt;
    func 	me.erase,&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.pm_trigger,&lt;br /&gt;
    func 	me.plusminus(),&lt;br /&gt;
    func 	me.clear(pressedTime),&lt;br /&gt;
    func 	me.erase(),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ListenerCollection ==&lt;br /&gt;
In order to update fields that are tied to a (potentially changing) property, fields that need a (potentially changing) property to compute their data can (and automatically will) register a property listener on the relevant properties whenever the relevant field is displayed. In order to unregister the listener for pages that are no longer displayed, the class CDU keeps a collection of the currently active listeners, such allowing the unregisterling for unneeded listeners.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ListenerCollection = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	add(prop, field_id, subpage_id, side, lsk_index),&lt;br /&gt;
    func 	clearAll(),&lt;br /&gt;
    func 	new(ptp=nil),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.listener_list,&lt;br /&gt;
    vector 	me.property_list,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Helping Functions and Classes =&lt;br /&gt;
&lt;br /&gt;
Although written for the CDU framework, these functions are fairly general and might be useful for other code projects. Please feel free to reuse them.&lt;br /&gt;
&lt;br /&gt;
== prepend ==&lt;br /&gt;
  var prepend = func(vec, elements...) &lt;br /&gt;
This function is the counterpart to the Nasal provided append. Instead of adding stuff to the end of the vector &amp;lt;tt&amp;gt;vec&amp;lt;/tt&amp;gt; is adds them at the front, '''altering the original vector'''. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== stack ==&lt;br /&gt;
  var stack = func(elements...)&lt;br /&gt;
Instead of appending or prepending, this function simply stacks its argument vectors and '''returns a new vector''', leaving the original function arguments unaltered. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== latitude_to_string ==&lt;br /&gt;
  var latitude_to_string = func(lat_deg)&lt;br /&gt;
Take a Nasal scalar as input variable and return something like N23°14.8 . Actually, as the &amp;quot;°&amp;quot; seems to have some trouble in Helvetica, is returns something like N23*14.8. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== longitude_to_string ==&lt;br /&gt;
  var longitude_to_string = func(lon_deg)&lt;br /&gt;
Take a Nasal scalar as input variable and return something like E123°14.8 . Actually, as the &amp;quot;°&amp;quot; seems to have some trouble in Helvetica, is returns something like E123*14.8. (Implemented in &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
== Timer ==&lt;br /&gt;
A timer can be made as an instance of this class. Each timer provides the functions tic and toc, the later returning the delta time passed.&lt;br /&gt;
  var timer1 = Timer.new(); # uses /sim/time/elapsed-sec as a time source&lt;br /&gt;
  var timer2 = Timer.new(non_default_time_source_variable); # provide an alternate source of time&lt;br /&gt;
  &lt;br /&gt;
  timer1.tic(); # start the internal timer on the default time source&lt;br /&gt;
  &lt;br /&gt;
  var passed_time = timer1.toc(); # stop and reset the timer, get back the passed time in seconds.&lt;br /&gt;
This class is implemented in &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Button ==&lt;br /&gt;
As an example for the use of the before mentioned timer, this is a generic button class to be used for all kinds of GUI interfaces. Although not used in the CDU, it still might be useful for other projects that require buttons to do several different things - depending on how long it has been pushed.&lt;br /&gt;
&lt;br /&gt;
  var b_clr = Button.new(&amp;quot;CLEAR&amp;quot;); # make a new button and give it a name, stored in Button.name&lt;br /&gt;
  &lt;br /&gt;
  b_clr.addButtonAction(func() {print(&amp;quot;NO delay&amp;quot;);} ); # zero delay is the default. This function will be executed if no other criteria are met&lt;br /&gt;
  b_clr.addButtonAction(func() {print(&amp;quot;2s delay&amp;quot;);},2 ); # this function will be executed if the button has been pressed longer than 2 seconds when released.&lt;br /&gt;
  b_clr.addButtonAction(func() {print(&amp;quot;1s delay&amp;quot;);},1 ); # this function will be executed if the button has been pressed longer than 1 seconds when released.&lt;br /&gt;
&lt;br /&gt;
The corresponding XML code for your model.xml could look like this:&lt;br /&gt;
  &amp;lt;animation&amp;gt;&lt;br /&gt;
  	&amp;lt;type&amp;gt;pick&amp;lt;/type&amp;gt;&lt;br /&gt;
        &amp;lt;!-- UPDATE the name of the button object to match you case --&amp;gt;&lt;br /&gt;
  	&amp;lt;object-name&amp;gt;Btn.clr&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  	&amp;lt;action&amp;gt;&lt;br /&gt;
  		&amp;lt;button&amp;gt;0&amp;lt;/button&amp;gt;&lt;br /&gt;
  		&amp;lt;repeatable&amp;gt;false&amp;lt;/repeatable&amp;gt;  &lt;br /&gt;
  		&amp;lt;binding&amp;gt;&lt;br /&gt;
  			&amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
 			&amp;lt;nowiki&amp;gt;&amp;lt;!-- UPDATE the namespace --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  			&amp;lt;script&amp;gt;&amp;lt;![CDATA[NAMESPACE.b_clr.pressed();]]&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  		&amp;lt;/binding&amp;gt;&lt;br /&gt;
  		&amp;lt;mod-up&amp;gt;&lt;br /&gt;
  			&amp;lt;binding&amp;gt;&lt;br /&gt;
  				&amp;lt;command&amp;gt;nasal&amp;lt;/command&amp;gt;&lt;br /&gt;
  				&amp;lt;nowiki&amp;gt;&amp;lt;!-- UPDATE the namespace --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
  				&amp;lt;script&amp;gt;&amp;lt;![CDATA[NAMESPACE.b_clr.released();]]&amp;gt;&amp;lt;/script&amp;gt;&lt;br /&gt;
  			&amp;lt;/binding&amp;gt;&lt;br /&gt;
  		&amp;lt;/mod-up&amp;gt;&lt;br /&gt;
  	&amp;lt;/action&amp;gt;&lt;br /&gt;
  &amp;lt;/animation&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The sequence in which functions are added does not matter, note how the example created the 2 s before the 1 s functions. As a result of this, the button has to be released to work, i.e. currently it is not possible to make the button do something if the button has been pressed longer than X s and still is pressed.&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31562</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31562"/>
		<updated>2011-05-09T18:45:33Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
These are the core classes in the CDU framework. The documentation should show a brief comment on what each variable or function is intended to do, particularly the ones that are important for the '''creation''' of an actual, content-filled CDU page.&lt;br /&gt;
&lt;br /&gt;
Although Nasal as such has no support for this, the internal stuff in a class is sectioned in three categories, borrowing language from &amp;lt;tt&amp;gt;C++&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''Static:''' Stuff in this section is mainly identified by being made directly as part of the &amp;lt;tt&amp;gt;hash&amp;lt;/tt&amp;gt; (as opposed to being ''tagged on'' by the the &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; constructor. Elements in here also follow a ''camelCase'' type of notation, whereas ''members'' use an ''underscore_naming_convetion''. Please note that although meant to be comparable to statics, in hindsight a lot of them would be better placed in the member section Public...&lt;br /&gt;
&lt;br /&gt;
* '''Public:''' Elements in here are created from inside the &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; constructor and follow an ''underscore_naming_convetion''. In a perfect world these would only be accessing functions, as exposing variables is always prone for trouble when the time for a redesign comes... Elements in here should be the only ones used in the creation of a page - in a perfect world.&lt;br /&gt;
&lt;br /&gt;
* '''Private:''' Elements in here are created from inside the &amp;lt;tt&amp;gt;new&amp;lt;/tt&amp;gt; constructor and follow an ''underscore_naming_convetion''. Although readable by everybody, access to these elements should be limited to functions in the static and public parts of the classes code. Particularly no page creation (user) code should need to access this information.&lt;br /&gt;
&lt;br /&gt;
'''Note:''' I know that I violate these rules. Yes. But I have rewritten the framework to often to (at this point) care much about it - particularly as it seems to be working. Please, feel free to correct the Nasal code I have written (which might involve the pain of revisiting the page creation sections... Sorry for that.) [[User:Hcc23|Hcc23]] 14:45, 9 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	formatOutput(input_data),&lt;br /&gt;
    func 	getScreenTextVector(),&lt;br /&gt;
    func 	new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.used_properties,&lt;br /&gt;
    vector 	me.line_data,&lt;br /&gt;
    scalar 	me.line_string_length,&lt;br /&gt;
    func 	me.enable(),&lt;br /&gt;
    func 	me.disable(),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
A field holds two lines, the label and the data line, as well as information about what the associated line select key does.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Field = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	new(label,data,key_action=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
  &lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.used_properties(),&lt;br /&gt;
    func 	me.lsk_binding(),&lt;br /&gt;
    func 	me.enable_lsk(),&lt;br /&gt;
    func 	me.disable_lsk(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    (Line)	me.label_line,	&lt;br /&gt;
    (Line) 	me.data_line,&lt;br /&gt;
    scalar 	me.lsk_active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
A SubPage is actually the main element in the CDU framework. It holds the content via its fields and manages the updating of the CDU screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var SubPage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    (Field) 	blankField,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	updateField(field, side, lsk_index),	&lt;br /&gt;
    func 	displayFields(field_vector, side),&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	new(parent_base_page,name=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar      me.separator,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    func 	me.register_field(field_pos,field),&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.parent,&lt;br /&gt;
    scalar      me.title,&lt;br /&gt;
    scalar      me.status,&lt;br /&gt;
    vector 	me.left_field,&lt;br /&gt;
    vector      me.right_field,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
A BasePage is exactly that: a base to hold sub pages. A base page most closely represents the concept of a '''page''' in a CDU.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var BasePage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	regiserInPropTree(path)&lt;br /&gt;
    func 	new(name,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.active_sub_page_id,&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    vector 	me.sub_pages,&lt;br /&gt;
    scalar 	me.title,&lt;br /&gt;
    scalar 	me.status,&lt;br /&gt;
    &lt;br /&gt;
  };  &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
The CDU is the main class for the instrument. Each simulated CDU should have one and only one CDU instance associated to it. This is intended to support multiple CDUs showing different content in the future.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var CDU = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    func 	M_ERROR(message_string),&lt;br /&gt;
    func 	M_WARNING(message_string),&lt;br /&gt;
    func 	M_NOTE(message_string),&lt;br /&gt;
    func 	M_HINT(message_string),&lt;br /&gt;
  &lt;br /&gt;
    func 	updateDisplay(),&lt;br /&gt;
    scalar 	activeBasePageID,&lt;br /&gt;
  &lt;br /&gt;
    (ScratchPad) 		scratchPad,&lt;br /&gt;
    (Timer) 			timer,&lt;br /&gt;
    (ListenerCollection) 	listOfListeners,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Additional Infrastructure =&lt;br /&gt;
The previous section was more concerned with the conceptually necessary pieces for a/the CDU. This section introduces the other elements the framework introduces in order to code a functional CDU.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ScratchPad ==&lt;br /&gt;
&lt;br /&gt;
The ScratchPad is the input/output line in the CDU(s). The scratch pas as such is kind of different from the rest of the CDU(s) as the scratch pad messages are truly static, i.e. they happen to be displayed on all CDUs in the cockpit, no matter what the individual CDU is otherwise showing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ScratchPad = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	messages,&lt;br /&gt;
    scalar 	deleteString, # &amp;quot;DELETE&amp;quot;~&amp;quot;&amp;quot;&lt;br /&gt;
    func 	displayScratchPad(),&lt;br /&gt;
    func 	new(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.input_string,&lt;br /&gt;
    func 	me.erase,&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.pm_trigger,&lt;br /&gt;
    func 	me.plusminus(),&lt;br /&gt;
    func 	me.clear(pressedTime),&lt;br /&gt;
    func 	me.erase(),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ListenerCollection ==&lt;br /&gt;
In order to update fields that are tied to a (potentially changing) property, fields that need a (potentially changing) property to compute their data can (and automatically will) register a property listener on the relevant properties whenever the relevant field is displayed. In order to unregister the listener for pages that are no longer displayed, the class CDU keeps a collection of the currently active listeners, such allowing the unregisterling for unneeded listeners.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ListenerCollection = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	add(prop, field_id, subpage_id, side, lsk_index),&lt;br /&gt;
    func 	clearAll(),&lt;br /&gt;
    func 	new(ptp=nil),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.listener_list,&lt;br /&gt;
    vector 	me.property_list,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31561</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31561"/>
		<updated>2011-05-09T18:29:21Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* CDU */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	formatOutput(input_data),&lt;br /&gt;
    func 	getScreenTextVector(),&lt;br /&gt;
    func 	new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.used_properties,&lt;br /&gt;
    vector 	me.line_data,&lt;br /&gt;
    scalar 	me.line_string_length,&lt;br /&gt;
    func 	me.enable(),&lt;br /&gt;
    func 	me.disable(),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
A field holds two lines, the label and the data line, as well as information about what the associated line select key does.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Field = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	new(label,data,key_action=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
  &lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.used_properties(),&lt;br /&gt;
    func 	me.lsk_binding(),&lt;br /&gt;
    func 	me.enable_lsk(),&lt;br /&gt;
    func 	me.disable_lsk(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    (Line)	me.label_line,	&lt;br /&gt;
    (Line) 	me.data_line,&lt;br /&gt;
    scalar 	me.lsk_active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
A SubPage is actually the main element in the CDU framework. It holds the content via its fields and manages the updating of the CDU screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var SubPage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    (Field) 	blankField,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	updateField(field, side, lsk_index),	&lt;br /&gt;
    func 	displayFields(field_vector, side),&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	new(parent_base_page,name=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar      me.separator,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    func 	me.register_field(field_pos,field),&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.parent,&lt;br /&gt;
    scalar      me.title,&lt;br /&gt;
    scalar      me.status,&lt;br /&gt;
    vector 	me.left_field,&lt;br /&gt;
    vector      me.right_field,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
A BasePage is exactly that: a base to hold sub pages. A base page most closely represents the concept of a '''page''' in a CDU.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var BasePage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	regiserInPropTree(path)&lt;br /&gt;
    func 	new(name,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.active_sub_page_id,&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    vector 	me.sub_pages,&lt;br /&gt;
    scalar 	me.title,&lt;br /&gt;
    scalar 	me.status,&lt;br /&gt;
    &lt;br /&gt;
  };  &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
The CDU is the main class for the instrument. Each simulated CDU should have one and only one CDU instance associated to it. This is intended to support multiple CDUs showing different content in the future.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var CDU = {&lt;br /&gt;
    # &amp;quot;STATIC&amp;quot;&lt;br /&gt;
    func 	M_ERROR(message_string),&lt;br /&gt;
    func 	M_WARNING(message_string),&lt;br /&gt;
    func 	M_NOTE(message_string),&lt;br /&gt;
    func 	M_HINT(message_string),&lt;br /&gt;
  &lt;br /&gt;
    func 	updateDisplay(),&lt;br /&gt;
    scalar 	activeBasePageID,&lt;br /&gt;
  &lt;br /&gt;
    (ScratchPad) 		scratchPad,&lt;br /&gt;
    (Timer) 			timer,&lt;br /&gt;
    (ListenerCollection) 	listOfListeners,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= Additional Infrastructure =&lt;br /&gt;
The previous section was more concerned with the conceptually necessary pieces for a/the CDU. This section introduces the other elements the framework introduces in order to code a functional CDU.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ScratchPad ==&lt;br /&gt;
&lt;br /&gt;
The ScratchPad is the input/output line in the CDU(s). The scratch pas as such is kind of different from the rest of the CDU(s) as the scratch pad messages are truly static, i.e. they happen to be displayed on all CDUs in the cockpit, no matter what the individual CDU is otherwise showing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ScratchPad = {&lt;br /&gt;
    # &amp;quot;STATIC&amp;quot;&lt;br /&gt;
    vector 	messages,&lt;br /&gt;
    scalar 	deleteString, # &amp;quot;DELETE&amp;quot;~&amp;quot;&amp;quot;&lt;br /&gt;
    func 	displayScratchPad(),&lt;br /&gt;
    func 	new(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;PUBLIC&amp;quot;&lt;br /&gt;
    scalar 	me.input_string,&lt;br /&gt;
    func 	me.erase,&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;PRIVATE&amp;quot;&lt;br /&gt;
    scalar 	me.pm_trigger,&lt;br /&gt;
    func 	me.plusminus(),&lt;br /&gt;
    func 	me.clear(pressedTime),&lt;br /&gt;
    func 	me.erase(),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ListenerCollection ==&lt;br /&gt;
In order to update fields that are tied to a (potentially changing) property, fields that need a (potentially changing) property to compute their data can (and automatically will) register a property listener on the relevant properties whenever the relevant field is displayed. In order to unregister the listener for pages that are no longer displayed, the class CDU keeps a collection of the currently active listeners, such allowing the unregisterling for unneeded listeners.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ListenerCollection = {&lt;br /&gt;
    # &amp;quot;STATIC&amp;quot;&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	add(prop, field_id, subpage_id, side, lsk_index),&lt;br /&gt;
    func 	clearAll(),&lt;br /&gt;
    func 	new(ptp=nil),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;PRIVATE&amp;quot;&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.listener_list,&lt;br /&gt;
    vector 	me.property_list,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31560</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31560"/>
		<updated>2011-05-09T18:23:31Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Supportive Infrastructure */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	formatOutput(input_data),&lt;br /&gt;
    func 	getScreenTextVector(),&lt;br /&gt;
    func 	new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.used_properties,&lt;br /&gt;
    vector 	me.line_data,&lt;br /&gt;
    scalar 	me.line_string_length,&lt;br /&gt;
    func 	me.enable(),&lt;br /&gt;
    func 	me.disable(),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
A field holds two lines, the label and the data line, as well as information about what the associated line select key does.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Field = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	new(label,data,key_action=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
  &lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.used_properties(),&lt;br /&gt;
    func 	me.lsk_binding(),&lt;br /&gt;
    func 	me.enable_lsk(),&lt;br /&gt;
    func 	me.disable_lsk(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    (Line)	me.label_line,	&lt;br /&gt;
    (Line) 	me.data_line,&lt;br /&gt;
    scalar 	me.lsk_active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
A SubPage is actually the main element in the CDU framework. It holds the content via its fields and manages the updating of the CDU screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var SubPage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    (Field) 	blankField,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	updateField(field, side, lsk_index),	&lt;br /&gt;
    func 	displayFields(field_vector, side),&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	new(parent_base_page,name=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar      me.separator,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    func 	me.register_field(field_pos,field),&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.parent,&lt;br /&gt;
    scalar      me.title,&lt;br /&gt;
    scalar      me.status,&lt;br /&gt;
    vector 	me.left_field,&lt;br /&gt;
    vector      me.right_field,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
A BasePage is exactly that: a base to hold sub pages. A base page most closely represents the concept of a '''page''' in a CDU.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var BasePage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	regiserInPropTree(path)&lt;br /&gt;
    func 	new(name,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.active_sub_page_id,&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    vector 	me.sub_pages,&lt;br /&gt;
    scalar 	me.title,&lt;br /&gt;
    scalar 	me.status,&lt;br /&gt;
    &lt;br /&gt;
  };  &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Additional Infrastructure =&lt;br /&gt;
The previous section was more concerned with the conceptually necessary pieces for a/the CDU. This section introduces the other elements the framework introduces in order to code a functional CDU.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ScratchPad ==&lt;br /&gt;
&lt;br /&gt;
The ScratchPad is the input/output line in the CDU(s). The scratch pas as such is kind of different from the rest of the CDU(s) as the scratch pad messages are truly static, i.e. they happen to be displayed on all CDUs in the cockpit, no matter what the individual CDU is otherwise showing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ScratchPad = {&lt;br /&gt;
    # &amp;quot;STATIC&amp;quot;&lt;br /&gt;
    vector 	messages,&lt;br /&gt;
    scalar 	deleteString, # &amp;quot;DELETE&amp;quot;~&amp;quot;&amp;quot;&lt;br /&gt;
    func 	displayScratchPad(),&lt;br /&gt;
    func 	new(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;PUBLIC&amp;quot;&lt;br /&gt;
    scalar 	me.input_string,&lt;br /&gt;
    func 	me.erase,&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;PRIVATE&amp;quot;&lt;br /&gt;
    scalar 	me.pm_trigger,&lt;br /&gt;
    func 	me.plusminus(),&lt;br /&gt;
    func 	me.clear(pressedTime),&lt;br /&gt;
    func 	me.erase(),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== ListenerCollection ==&lt;br /&gt;
In order to update fields that are tied to a (potentially changing) property, fields that need a (potentially changing) property to compute their data can (and automatically will) register a property listener on the relevant properties whenever the relevant field is displayed. In order to unregister the listener for pages that are no longer displayed, the class CDU keeps a collection of the currently active listeners, such allowing the unregisterling for unneeded listeners.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var ListenerCollection = {&lt;br /&gt;
    # &amp;quot;STATIC&amp;quot;&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	add(prop, field_id, subpage_id, side, lsk_index),&lt;br /&gt;
    func 	clearAll(),&lt;br /&gt;
    func 	new(ptp=nil),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;PRIVATE&amp;quot;&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.listener_list,&lt;br /&gt;
    vector 	me.property_list,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31559</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31559"/>
		<updated>2011-05-09T18:07:49Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* BasePage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	formatOutput(input_data),&lt;br /&gt;
    func 	getScreenTextVector(),&lt;br /&gt;
    func 	new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.used_properties,&lt;br /&gt;
    vector 	me.line_data,&lt;br /&gt;
    scalar 	me.line_string_length,&lt;br /&gt;
    func 	me.enable(),&lt;br /&gt;
    func 	me.disable(),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
A field holds two lines, the label and the data line, as well as information about what the associated line select key does.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Field = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	new(label,data,key_action=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
  &lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.used_properties(),&lt;br /&gt;
    func 	me.lsk_binding(),&lt;br /&gt;
    func 	me.enable_lsk(),&lt;br /&gt;
    func 	me.disable_lsk(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    (Line)	me.label_line,	&lt;br /&gt;
    (Line) 	me.data_line,&lt;br /&gt;
    scalar 	me.lsk_active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
A SubPage is actually the main element in the CDU framework. It holds the content via its fields and manages the updating of the CDU screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var SubPage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    (Field) 	blankField,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	updateField(field, side, lsk_index),	&lt;br /&gt;
    func 	displayFields(field_vector, side),&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	new(parent_base_page,name=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar      me.separator,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    func 	me.register_field(field_pos,field),&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.parent,&lt;br /&gt;
    scalar      me.title,&lt;br /&gt;
    scalar      me.status,&lt;br /&gt;
    vector 	me.left_field,&lt;br /&gt;
    vector      me.right_field,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
A BasePage is exactly that: a base to hold sub pages. A base page most closely represents the concept of a '''page''' in a CDU.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var BasePage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	regiserInPropTree(path)&lt;br /&gt;
    func 	new(name,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.active_sub_page_id,&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    vector 	me.sub_pages,&lt;br /&gt;
    scalar 	me.title,&lt;br /&gt;
    scalar 	me.status,&lt;br /&gt;
    &lt;br /&gt;
  };  &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Supportive Infrastructure =&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31558</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31558"/>
		<updated>2011-05-09T18:01:38Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* SubPage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	formatOutput(input_data),&lt;br /&gt;
    func 	getScreenTextVector(),&lt;br /&gt;
    func 	new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.used_properties,&lt;br /&gt;
    vector 	me.line_data,&lt;br /&gt;
    scalar 	me.line_string_length,&lt;br /&gt;
    func 	me.enable(),&lt;br /&gt;
    func 	me.disable(),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
A field holds two lines, the label and the data line, as well as information about what the associated line select key does.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Field = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	new(label,data,key_action=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
  &lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.used_properties(),&lt;br /&gt;
    func 	me.lsk_binding(),&lt;br /&gt;
    func 	me.enable_lsk(),&lt;br /&gt;
    func 	me.disable_lsk(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    (Line)	me.label_line,	&lt;br /&gt;
    (Line) 	me.data_line,&lt;br /&gt;
    scalar 	me.lsk_active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
A SubPage is actually the main element in the CDU framework. It holds the content via its fields and manages the updating of the CDU screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var SubPage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    (Field) 	blankField,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	updateField(field, side, lsk_index),	&lt;br /&gt;
    func 	displayFields(field_vector, side),&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	new(parent_base_page,name=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar      me.separator,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    func 	me.register_field(field_pos,field),&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.parent,&lt;br /&gt;
    scalar      me.title,&lt;br /&gt;
    scalar      me.status,&lt;br /&gt;
    vector 	me.left_field,&lt;br /&gt;
    vector      me.right_field,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Supportive Infrastructure =&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31557</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31557"/>
		<updated>2011-05-09T18:01:28Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* SubPage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	formatOutput(input_data),&lt;br /&gt;
    func 	getScreenTextVector(),&lt;br /&gt;
    func 	new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.used_properties,&lt;br /&gt;
    vector 	me.line_data,&lt;br /&gt;
    scalar 	me.line_string_length,&lt;br /&gt;
    func 	me.enable(),&lt;br /&gt;
    func 	me.disable(),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
A field holds two lines, the label and the data line, as well as information about what the associated line select key does.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Field = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	new(label,data,key_action=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
  &lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.used_properties(),&lt;br /&gt;
    func 	me.lsk_binding(),&lt;br /&gt;
    func 	me.enable_lsk(),&lt;br /&gt;
    func 	me.disable_lsk(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    (Line)	me.label_line,	&lt;br /&gt;
    (Line) 	me.data_line,&lt;br /&gt;
    scalar 	me.lsk_active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
A SubPage is actually the main element in the CDU framework. It holds the content via its fields and manages the updating of the CDU screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var SubPage = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    (Field) 	blankField,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	updateField(field, side, lsk_index),	&lt;br /&gt;
    func 	displayFields(field_vector, side),&lt;br /&gt;
    func 	displayPage(),&lt;br /&gt;
    func 	new(parent_base_page,name=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar      me.separator,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    func 	me.register_field(field_pos,field),&lt;br /&gt;
    func 	me.activate(),&lt;br /&gt;
    (Field) 	me.home&lt;br /&gt;
&lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.parent,&lt;br /&gt;
    scalar      me.title,&lt;br /&gt;
    scalar      me.status,&lt;br /&gt;
    vector 	me.left_field,&lt;br /&gt;
    vector      me.right_field,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Supportive Infrastructure =&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31539</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31539"/>
		<updated>2011-05-07T14:36:55Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Field */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	formatOutput(input_data),&lt;br /&gt;
    func 	getScreenTextVector(),&lt;br /&gt;
    func 	new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.used_properties,&lt;br /&gt;
    vector 	me.line_data,&lt;br /&gt;
    scalar 	me.line_string_length,&lt;br /&gt;
    func 	me.enable(),&lt;br /&gt;
    func 	me.disable(),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
A field holds two lines, the label and the data line, as well as information about what the associated line select key does.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Field = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	new(label,data,key_action=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
  &lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.used_properties(),&lt;br /&gt;
    func 	me.lsk_binding(),&lt;br /&gt;
    func 	me.enable_lsk(),&lt;br /&gt;
    func 	me.disable_lsk(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    (Line)	me.label_line,	&lt;br /&gt;
    (Line) 	me.data_line,&lt;br /&gt;
    scalar 	me.lsk_active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Supportive Infrastructure =&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31538</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31538"/>
		<updated>2011-05-07T14:36:17Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Line */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	formatOutput(input_data),&lt;br /&gt;
    func 	getScreenTextVector(),&lt;br /&gt;
    func 	new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.used_properties,&lt;br /&gt;
    vector 	me.line_data,&lt;br /&gt;
    scalar 	me.line_string_length,&lt;br /&gt;
    func 	me.enable(),&lt;br /&gt;
    func 	me.disable(),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    scalar 	me.active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
A field holds two lines, the label and the data line, as well as information about what the associated line select key does.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Field = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	new(label,data,key_action=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
  &lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func        me.used_properties(),&lt;br /&gt;
    func 	me.lsk_binding(),&lt;br /&gt;
    func 	me.enable_lsk(),&lt;br /&gt;
    func 	me.disable_lsk(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    (Line)	me.label_line,	&lt;br /&gt;
    (Line) 	me.data_line,&lt;br /&gt;
    scalar 	me.lsk_active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Supportive Infrastructure =&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31537</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31537"/>
		<updated>2011-05-07T14:34:41Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Field */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    hash 	byID,&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	formatOutput(input_data),&lt;br /&gt;
    func 	getScreenTextVector(),&lt;br /&gt;
    func 	new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.used_properties,&lt;br /&gt;
    vector 	me.line_data,&lt;br /&gt;
    scalar 	me.line_string_length,&lt;br /&gt;
    scalar 	me.active,&lt;br /&gt;
    func 	me.enable(),&lt;br /&gt;
    func 	me.disable(),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
A field holds two lines, the label and the data line, as well as information about what the associated line select key does.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Field = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    vector 	byID,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	new(label,data,key_action=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
  &lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func        me.used_properties(),&lt;br /&gt;
    func 	me.lsk_binding(),&lt;br /&gt;
    func 	me.enable_lsk(),&lt;br /&gt;
    func 	me.disable_lsk(),&lt;br /&gt;
  &lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    (Line)	me.label_line,	&lt;br /&gt;
    (Line) 	me.data_line,&lt;br /&gt;
    scalar 	me.lsk_active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Supportive Infrastructure =&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31536</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31536"/>
		<updated>2011-05-07T14:33:37Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Field */  Added Structure&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    hash 	byID,&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	formatOutput(input_data),&lt;br /&gt;
    func 	getScreenTextVector(),&lt;br /&gt;
    func 	new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.used_properties,&lt;br /&gt;
    vector 	me.line_data,&lt;br /&gt;
    scalar 	me.line_string_length,&lt;br /&gt;
    scalar 	me.active,&lt;br /&gt;
    func 	me.enable(),&lt;br /&gt;
    func 	me.disable(),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
A field holds two lines, the label and the data line, as well as information about what the associated line select key does.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Field = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    hash 	byID,&lt;br /&gt;
    func 	registerInPropTree(path=nil),&lt;br /&gt;
    func 	new(label,data,key_action=nil,ptp=nil),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
&lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func 	me.get_label_line(),&lt;br /&gt;
    func        me.used_properties(),&lt;br /&gt;
    func 	me.lsk_binding(),&lt;br /&gt;
    func 	me.enable_lsk(),&lt;br /&gt;
    func 	me.disable_lsk(),&lt;br /&gt;
&lt;br /&gt;
    # &amp;quot;Private&amp;quot;&lt;br /&gt;
    (Line)	me.label_line,	&lt;br /&gt;
    (Line) 	me.data_line,&lt;br /&gt;
    scalar 	me.lsk_active,&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Supportive Infrastructure =&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31535</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31535"/>
		<updated>2011-05-07T14:25:13Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Line */  Adde types&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    hash 	byID,&lt;br /&gt;
    func 	registerInPropTree(path),&lt;br /&gt;
    func 	formatOutput(input_data),&lt;br /&gt;
    func 	getScreenTextVector(),&lt;br /&gt;
    func 	new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    scalar 	me.id,&lt;br /&gt;
    scalar 	me.ptp,&lt;br /&gt;
    vector 	me.used_properties,&lt;br /&gt;
    vector 	me.line_data,&lt;br /&gt;
    scalar 	me.line_string_length,&lt;br /&gt;
    scalar 	me.active,&lt;br /&gt;
    func 	me.enable(),&lt;br /&gt;
    func 	me.disable(),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Supportive Infrastructure =&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31534</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31534"/>
		<updated>2011-05-07T14:22:18Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Line */  Added variables&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
The line class represents data to be shown on a row of the CDU's display matrix. This does not mean that a line has to span a complete row of the CDU's display matrix. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  var Line = {&lt;br /&gt;
    # &amp;quot;Static&amp;quot;&lt;br /&gt;
    hash byID,&lt;br /&gt;
    func registerInPropTree(path),&lt;br /&gt;
    func formatOutput(input_data),&lt;br /&gt;
    func getScreenTextVector(),&lt;br /&gt;
    func new(line_data,ptp),&lt;br /&gt;
    &lt;br /&gt;
    # &amp;quot;Public&amp;quot;&lt;br /&gt;
    me.id,&lt;br /&gt;
    me.ptp,&lt;br /&gt;
    me.used_properties,&lt;br /&gt;
    me.line_data,&lt;br /&gt;
    me.line_string_length,&lt;br /&gt;
    me.active,&lt;br /&gt;
    me.enable(),&lt;br /&gt;
    me.disable(),&lt;br /&gt;
  };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Supportive Infrastructure =&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31533</id>
		<title>Nasal CDU Framework</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Nasal_CDU_Framework&amp;diff=31533"/>
		<updated>2011-05-07T14:07:02Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: Started with the pages outline&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page is a rather technical description of the Nasal code for the framework used to implement a Boeing style [[CDU]].&lt;br /&gt;
&lt;br /&gt;
{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
'''Note:''' Although this is meant as a documentation for the code, it obviously will (always) be (slightly) outdated. However, after reading through this page, the actual source code at https://gitorious.org/fg/fgdata/trees/master/Aircraft/Instruments-3d/cdu should not present any major surprises. [[User:Hcc23|Hcc23]] 10:07, 7 May 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Basic Classes =&lt;br /&gt;
&lt;br /&gt;
== Line ==&lt;br /&gt;
&lt;br /&gt;
== Field ==&lt;br /&gt;
&lt;br /&gt;
== SubPage ==&lt;br /&gt;
&lt;br /&gt;
== BasePage ==&lt;br /&gt;
&lt;br /&gt;
== CDU ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Supportive Infrastructure =&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=31532</id>
		<title>Howto:Coding a Boeing CDU</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=31532"/>
		<updated>2011-05-07T13:55:14Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* The Code Framework */  Linked to new page on framework alone&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
[[User:Gijs|Gijs]] has started an effort to bring a generic Boeing [[CDU]] to [[FlightGear]]. This page tries to describe the coding for this effort.&lt;br /&gt;
&lt;br /&gt;
= The Sources =&lt;br /&gt;
The [[CDU]] currently resides in '''$FGDATA/Aircraft/Instruments-3d/cdu/'''.&lt;br /&gt;
&lt;br /&gt;
'''Graphics''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.ac&amp;lt;/tt&amp;gt;: This is a [[AC3D]] file, describing the 3D outline of the CDU model.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_brown.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_grey.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
&lt;br /&gt;
'''XML''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;: This is the main [[XML]] file, providing the direct interface between the 3D model and the code. This file also defines the keypress interactions and the positioning of the text to be displayed in the screen.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display-matrix-text.xml&amp;lt;/tt&amp;gt;: An OSGText &amp;quot;model&amp;quot;, used as a baseline for the texts on the screen. Compare to &amp;lt;tt&amp;gt;README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Nasal''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;: This is the main [[Nasal]] script file to be edited by the ''user'' of the CDU Nasal framework.&lt;br /&gt;
* &amp;lt;tt&amp;gt;cdu_page_framework.nas&amp;lt;/tt&amp;gt;: This is the main file of the CDU framework. It defines the main ''classes'' used for the CDU.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;: This file contains the Nasal relevant for the dispaly matrix. This code might be useful for other complex screen-based instruments.&lt;br /&gt;
* &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;: This file contains functions which I found useful for my project, but which are totally generic and could be used for other stuff as well.&lt;br /&gt;
* &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;: This file contains a rudimentary timer ''class'' and an example of how to incorporate this with a generic class for an instrument button, allowing the button to call different Nasal scripts, depending on how long it has been pressed. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;README&amp;lt;/tt&amp;gt;: Well, a readme.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Loading a CDU into an Aircraft ==&lt;br /&gt;
Here is how the CDU is loaded into the Boeing 777-200:&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;777-22ER-set.xml&amp;lt;/tt&amp;gt; the Nasal node is expanded as follows:&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- generic for the CDU --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/helping_functions.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/timer.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/cdu_page_framework.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;nowiki&amp;gt;&amp;lt;!-- specific for the B777 --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/b777_cdu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
Note the difference in the framework files and the actual ''instance'' used for this aircraft. To code pages for the CDU, one would normally not have to mess with the framework files. [[User:Hcc23|Hcc23]]&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Somewhere in the actual 3D model of the aircraft the &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; for the 3D model of the CDU has to be loaded. I haven't looked for that yet as that was already done for the 777-200. [[User:Hcc23|Hcc23]] 14:42, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== 3D Graphics ==&lt;br /&gt;
The 3D model resides in the file '''&amp;lt;tt&amp;gt;$FGDATA/Models/Cockpit/Instruments/CDU/cdu.ac&amp;lt;/tt&amp;gt;'''. This is a [[AC3D]] file format, but it should be importable by [[Blender]].&lt;br /&gt;
{|&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| [[File:CDU_3D_wireframe.png|thumb|270px|The wireframe of the 3D model and the corresponding coordinate system. ATTENTION: the axis are not right: RED is +X, GREEN is +Z, BLUE is -Y !]]&lt;br /&gt;
| [[File:CDU.png|thumb|270px|The texture of the CDU, a 512x512 PNG bitmap.]]&lt;br /&gt;
| [[File:CDU_3D_textures.png|thumb|270px|The resulting 3D model, after the textures have been added.]]&lt;br /&gt;
|}&lt;br /&gt;
The model also specifies the model internal coordinate system. It is indicated in the pictures through the corresponding axis: X (red), Y (green), and Z (blue). The origin of this coordinate system seems to coincide with the geometric center of the back plane of the [[CDU]], i.e. the YZ-plane is coplanar with the back of the [[CDU]]. The unit of the coordinate system is the SI unit ''Meter''.&lt;br /&gt;
&lt;br /&gt;
The 3D model has bindings defined to each button. So when a certain button is clicked, something happens. Right now most buttons are only used&lt;br /&gt;
to open other [[CDU]]-pages.&lt;br /&gt;
&lt;br /&gt;
=== The Screen of the CDU ===&lt;br /&gt;
With respect to the model coordinate frame, the screen is the rectangle given by:&lt;br /&gt;
&lt;br /&gt;
  Top edge:   z= 0.111, x=0.004&lt;br /&gt;
  Lower edge: z= 0.019, x=0.004&lt;br /&gt;
  Left edge:  y=-0.051, x=0.004&lt;br /&gt;
  Right edge: y= 0.051, x=0.004&lt;br /&gt;
&lt;br /&gt;
= The Code Framework =&lt;br /&gt;
&lt;br /&gt;
This is a rough overview on the internal framework of the CDU code. A more detailed descriptions can be found at the [[Nasal CDU Framework]] page.&lt;br /&gt;
&lt;br /&gt;
The CDU framework is implemented following some standard object-oriented ideas, completely implemented in Nasal. All variables are instantiated using &amp;lt;tt&amp;gt;var&amp;lt;/tt&amp;gt; so that the global namespace should not be tainted.&lt;br /&gt;
&lt;br /&gt;
The idea for the framework stems from the fact that a CDU is based upon the concept of ''pages'', some of which could occupy several screens. This, in conjunction with the idea of the ''fields'' (stipulated from the screen layout of the CDU) resulted in the following framework:&lt;br /&gt;
  CDU&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | | |-Line&lt;br /&gt;
  | | | |-Line&lt;br /&gt;
  | | | &lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |  |-Line&lt;br /&gt;
  | | |  |-Line&lt;br /&gt;
  | | |&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | | &lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | |&lt;br /&gt;
  | |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  |   |&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-...&lt;br /&gt;
Well, you get the idea....&lt;br /&gt;
&lt;br /&gt;
These four  ''classes'' (BasePage, SubPage, Field, Line) are defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;. The constructors are generally called &amp;lt;tt&amp;gt;.new()&amp;lt;/tt&amp;gt;, all ''members'' are created within the constructors, all ''static'' parts are implemented directly on the hash level.&lt;br /&gt;
&lt;br /&gt;
Beside these four classes the class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;) is used to house the actual text to be printed.&lt;br /&gt;
&lt;br /&gt;
All text is then kept internal to Nasal within the before-mentioned structure. The text is then also kept in the FlightGear property tree so that an interface to osgtext can be established via &amp;lt;tt&amp;gt;boeing_cdu.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' There is a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable set in the CDU framework. Setting this variable to non-zero enables a bunch of console printouts, implemented via &amp;lt;tt&amp;gt;DEBUG&amp;gt;debug_level?print('....'):;&amp;lt;/tt&amp;gt; Furthermore, when calling a constructor, the parameter &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt; (for path-to-property) can be set, enabling some member variables of the classes to register themselves in the property tree, allowing an easier debugging during runtime. [[User:Hcc23|Hcc23]] 15:20, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
Maybe looking at the actual code is the easiest way of understanding how the framework works. (I also tried to be fairly explicit in my in-code comments, so looking at the sources should actually be helpful, too. [[User:Hcc23|Hcc23]] 15:46, 8 April 2011 (EDT))&lt;br /&gt;
&lt;br /&gt;
As the framework is separate from the ''instanciation'', let's focus on that as that is the part a ''user'' should care mostly about. The relevant file for the Boeing 777-200 is &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Preliminaries===&lt;br /&gt;
  #####################################################&lt;br /&gt;
  # These variables have already been defined in &lt;br /&gt;
  # cdu_page_framework but can (?) be redifined here &lt;br /&gt;
  # for slightly changed versions.&lt;br /&gt;
  #####################################################&lt;br /&gt;
  &lt;br /&gt;
  var ROWS = 14; 	# the number of lines the CDU has&lt;br /&gt;
  var COLS = 24; 	# the number of characters each line can hold&lt;br /&gt;
  var PROP = &amp;quot;/instrumentation/cdu&amp;quot;; 	# generic path to the properties of this CDU&lt;br /&gt;
  var DEBUG = 1; # enable a more verbose &amp;quot;debug&amp;quot; mode, i.e. register all kinds of stuff in the property tree&lt;br /&gt;
  &lt;br /&gt;
  resetDisplayMatrix();&lt;br /&gt;
This essential defines the size of the dispaly matrix, enables the debug printout and clears the display matrix in the property tree.&lt;br /&gt;
(&amp;lt;tt&amp;gt;resetDisplayMatrix();&amp;lt;/tt&amp;gt; fills the complete display matrix with spaces ( ) and also set the style to &amp;lt;tt&amp;gt;&amp;quot;off&amp;quot;&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
===Making the BasePages===&lt;br /&gt;
  # make the pages&lt;br /&gt;
  var page_menu      = BasePage.new(&amp;quot;MENU&amp;quot;,PROP~&amp;quot;/page_menu&amp;quot;); &lt;br /&gt;
  KeyBinding[&amp;quot;MENU&amp;quot;] = func() {page_menu.displayPage(); }; # Note : do NOT forget to wrap displayPage with a function!&lt;br /&gt;
  var page_index     = BasePage.new(&amp;quot;INDEX&amp;quot;,PROP~&amp;quot;/page_index&amp;quot;); &lt;br /&gt;
  var page_ident     = BasePage.new(&amp;quot;IDENT&amp;quot;,PROP~&amp;quot;/page_ident&amp;quot;); &lt;br /&gt;
  var page_pos       = BasePage.new(&amp;quot;POS&amp;quot;,PROP~&amp;quot;/page_pos&amp;quot;); &lt;br /&gt;
  var page_perf      = BasePage.new(&amp;quot;PERF&amp;quot;,PROP~&amp;quot;/page_perf&amp;quot;); &lt;br /&gt;
  var page_thrustLim = BasePage.new(&amp;quot;THRUST LIM&amp;quot;,PROP~&amp;quot;/page_thurstLim&amp;quot;); &lt;br /&gt;
  var page_takeoff   = BasePage.new(&amp;quot;TAKEOFF&amp;quot;,PROP~&amp;quot;/page_takeoff&amp;quot;); &lt;br /&gt;
  var page_approach  = BasePage.new(&amp;quot;APPROACH&amp;quot;,PROP~&amp;quot;/page_approach&amp;quot;); &lt;br /&gt;
  var page_navData   = BasePage.new(&amp;quot;NAV DATA&amp;quot;,PROP~&amp;quot;/page_navData&amp;quot;); &lt;br /&gt;
  var page_maint     = BasePage.new(&amp;quot;MAINT&amp;quot;,PROP~&amp;quot;/page_maint&amp;quot;); &lt;br /&gt;
This section creates the base pages of the CDU. The constructor for base pages is this one:&lt;br /&gt;
  new: func(name,ptp=nil) {...};&lt;br /&gt;
What this essentially does is creating a container to house sub pages. The &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element is used as the title of the page (but this could be overwritten in a sub page), the &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;, if set, registers the base page at that path. (However, if the &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable is set, the the pages are registered by their internal ID in a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; path underneath the CDU.)&lt;br /&gt;
&lt;br /&gt;
When a base page constructor is called, it also creates a ''home''-method. This function can be used to make the corresponding base page the active page, i.e. display that page. As you can see above, the corresponding method of the MENU page is assigned to the related button of the CDU. &amp;lt;tt&amp;gt;KeyBinding&amp;lt;/tt&amp;gt; is defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;, for a list of the available buttons see &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Making a SubPage (and the corresponding Fields)===&lt;br /&gt;
  #######################&lt;br /&gt;
  # DETAILS PAGE MENU&lt;br /&gt;
  #######################&lt;br /&gt;
  #&lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make details for page &amp;quot;~&amp;quot;MENU&amp;quot;):;&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_menu_default = SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,&amp;quot;FMC&amp;quot;,page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
  &lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_menu_default.activate();&lt;br /&gt;
This code section starts to fill in the details of the page MENU. As outlined in the framework, each base page houses sub pages, which in turn house the fields (which hold the actual content). So we need to start by making a sub page:&lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_menu_default = SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
The constructor for a sub page looks like this:&lt;br /&gt;
  new: func(parent_base_page,name=nil,ptp=nil) {...};&lt;br /&gt;
The elements are fairly straight forward:&lt;br /&gt;
* parent_base_page: parent node of this sub page (which is a base page). Note that this is not the name of that page, but the actual page, i.e. put down the name of the variable you made earlier. Here, this is a sub page of &amp;lt;tt&amp;gt;page_menu&amp;lt;/tt&amp;gt;, i.e. the MENU page, which was made earlier.&lt;br /&gt;
* name: similar to the name of a base page, it is used as the title entry of the sub page. If a sub page has a name (which it doesn't need to have), the name of the sub page overwrites the name of the base page, such allowing for slightly different titles on each &amp;quot;screen&amp;quot; of a CDU &amp;quot;page&amp;quot;. Note, however, that the display of the page count is taken care of, i.e. you do not have to put that into the title.&lt;br /&gt;
* ptp: same as with the base page. Also identical, the registration is changed to registration by ID when the DEBUG variable is non-zero.&lt;br /&gt;
&lt;br /&gt;
After a sub page has been made, one needs to make fields to actually hold content:&lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,&amp;quot;FMC&amp;quot;,page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
The first part creates a field, the field constructor is:&lt;br /&gt;
  new: func(label,data,key_action=nil,ptp=nil) {...};&lt;br /&gt;
This constructor is a little more complex than the previous ones:&lt;br /&gt;
* &amp;lt;tt&amp;gt;label&amp;lt;/tt&amp;gt;: the entry for the label line (the top line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;data&amp;lt;/tt&amp;gt;: the entry for data line (the lower line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;: as fields have an line select key associated with them, &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;, a function element, determines what happens when the LSK next to the data line is pressed.&lt;br /&gt;
* &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;: registering the field. As for base and sub pages, a non-zero DEBUG changes the ptp.&lt;br /&gt;
&lt;br /&gt;
In order to make the construction of a field a little more convenient, some very limited type of constructor overloading is incorporated. Both lines could be initialized with either an element of type &amp;lt;tt&amp;gt;ScreenText.new()&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;), i.e. a hash, or it can be initialized with a vector or elements, i.e. with &amp;lt;tt&amp;gt;[ScreenText.new() ScreenText.new() ...]&amp;lt;/tt&amp;gt;. (More on why this is nice to have later.)&lt;br /&gt;
&lt;br /&gt;
 # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
 page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
This part of the code puts this field into the top-left position in the sub page. Each sub page has two columns (&amp;lt;tt&amp;gt;SubPage.left_field[]&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;SubPage.right_field[]&amp;lt;/tt&amp;gt;) of six elements each. The columns are zero indexed.&lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_menu_default.activate();&lt;br /&gt;
This part activates this sup page. Sub page activation is slightly different from base page displaying. The later jumps to the base page and displays whatever sub page is active, &amp;lt;tt&amp;gt;SubPage.activate()&amp;lt;/tt&amp;gt; activates the corresponding sub page in the parent base page and then calls the display function of that page, effectively displaying the sub page.&lt;br /&gt;
&lt;br /&gt;
===Making a more complex SubPage===&lt;br /&gt;
Here just the code:&lt;br /&gt;
  #######################&lt;br /&gt;
  # DETAILS PAGE IDENT&lt;br /&gt;
  #######################&lt;br /&gt;
  #&lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make details for page &amp;quot;~&amp;quot;IDENT&amp;quot;):;&lt;br /&gt;
  &lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_ident_default = SubPage.new(page_ident,name=nil,ptp=&amp;quot;/sub_default&amp;quot;); &lt;br /&gt;
  &lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make fields for page &amp;quot;~&amp;quot;IDENT&amp;quot;):;&lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_model = Field.new(&amp;quot;MODEL&amp;quot;,ScreenText.new(['%s','/instrumentation/cdu/ident/model'],ScreenText[&amp;quot;WHITE&amp;quot;]));&lt;br /&gt;
  var field_engines = Field.new(&amp;quot;ENGINES&amp;quot;,ScreenText.new(['%s','/instrumentation/cdu/ident/engines'],ScreenText[&amp;quot;WHITE&amp;quot;]));&lt;br /&gt;
  var field_navData = Field.new(&amp;quot;NAV DATA&amp;quot;,&amp;quot;----&amp;quot;); &lt;br /&gt;
  var field_navData_active = Field.new(&amp;quot;ACTIVE&amp;quot;,&amp;quot;----&amp;quot;);&lt;br /&gt;
  var field_navData_inactive = Field.new(ScreenText.new(&amp;quot;INACTIVE&amp;quot;,ScreenText[&amp;quot;off&amp;quot;],nil),&amp;quot;----&amp;quot;); &lt;br /&gt;
  var field_dragFf = Field.new(&amp;quot;DRAG/FF&amp;quot;,&amp;quot;+0.0/+0.0&amp;quot;); &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_ident_default.left_field[0]=field_model;&lt;br /&gt;
  page_ident_default.left_field[1]=field_navData;&lt;br /&gt;
  page_ident_default.left_field[5]=page_index.home;&lt;br /&gt;
  page_ident_default.right_field[0]=field_engines;&lt;br /&gt;
  page_ident_default.right_field[1]=field_navData_active;&lt;br /&gt;
  page_ident_default.right_field[2]=field_navData_inactive;&lt;br /&gt;
  page_ident_default.right_field[4]=field_dragFf;&lt;br /&gt;
  page_ident_default.right_field[5]=page_pos_init.home;&lt;br /&gt;
  &lt;br /&gt;
  # place the separators&lt;br /&gt;
  page_ident_default.separators = [11];&lt;br /&gt;
  &lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_ident_default.activate();&lt;br /&gt;
The only new thing here is the use of the more complex version of the screen text constructor and the line&lt;br /&gt;
   page_ident_default.right_field[5]=page_pos_init.home;&lt;br /&gt;
What this does is assigning an auto-generate field of a sub page to a field in another sub page. Thes auto-generated fields can be used to directly activate these sub pages.&lt;br /&gt;
&lt;br /&gt;
= The CDU Screen = &lt;br /&gt;
One of the major problems of the CDU is the representation of the actual screen. According to the Honeywell manual, the CDU utilized by Boeing has a fixed setup.&lt;br /&gt;
&lt;br /&gt;
== Details of the (LCD) Screen ==&lt;br /&gt;
The LCD has '''14 lines''' with a total of '''24 characters per line'''. The page format is formatted as follows:&lt;br /&gt;
&lt;br /&gt;
* Title Field: The top line of the display area. Id identifies the subject or title of the data displayed on the page in view. It also identifies page number and the number of pages in series, e.g., &amp;lt;tt&amp;gt;1/2&amp;lt;/tt&amp;gt; identifies a page as the first in a series of two pages.&lt;br /&gt;
* Left Field: 6 pairs of lines, 11 characters per line. It extends from the left side of the screen to the center. The pilot has access to one line of each pair through a LSK (Line-Select Key) on the left side of the CDU. A line pair is made up of a label and a data line.&lt;br /&gt;
* Right Field: This field is similar to the left field, extending from the center of the screen to the right side. Pilot access is available by a LSK on the right side. &lt;br /&gt;
* Scratchpad: The bottom line of the display screen. This line displays alphanumeric data or messages. Data can be entered with the alphanumeric keys or the LSK, or by the FMC. Scratchpad entry cannot, normally, be made with a FMC message in the scratchpad. Scratchpad entries are independent of page selection, and remain until cleared even when page changes occur. Scratchpad data entries and erases affect only the associated CDU. Messages can appear and be erased on both CDUs simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Internal Representation ==&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The utilizes display matrix, showing the text bounding boxes for clarity.]]&lt;br /&gt;
As the screen has a &amp;quot;fixed&amp;quot; resolution, internally the screen is represented as a 14-by-24(-by-2) matrix. The zero-indexed matrix is held in the property tree:&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal double-type variable (although it is only integers).&lt;br /&gt;
&lt;br /&gt;
The style of the char is encoded via a binary key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt;  7&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name (used in the Nasal code for the CDU), which is resolved into a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
the first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;). The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet implemented. [[User:Hcc23|Hcc23]] 14:01, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Nasal Code ==&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;.&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields. Several elements can be concattenated in a single line by stacking them in a vector. The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text; or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background.&lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the text element. Here some limited constructor overloading can be used.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  var test_text = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  var test_prop = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
The last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;));&lt;br /&gt;
Furthermore, whenever a property is used in a screen text element on a subpage, the suppage, when displayed, registers listeners on all utilized properties, resulting in updated data on the screen. When the sup page is changed, the listeners are de-registered.&lt;br /&gt;
&lt;br /&gt;
== XML Code ==&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== Generating the offset code ===&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= The Property Tree =&lt;br /&gt;
&lt;br /&gt;
The [[CDU]] also has some properties in the general [[FlightGear]] [[Property Tree]].&lt;br /&gt;
In general it is located in &amp;lt;code&amp;gt;/instrumentation/cdu/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= A Brief History of the Boeing CDU in FlightGear =&lt;br /&gt;
Find some more information on the [[CDU]] at these pages:&lt;br /&gt;
* [[CDU]]&lt;br /&gt;
* [[Howto: Implement a Control Display Unit]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Animate_models&amp;diff=31354</id>
		<title>Howto:Animate models</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Animate_models&amp;diff=31354"/>
		<updated>2011-04-28T13:43:47Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Conditions */  added some details on the order of comparisons&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The real world is full of motion. To simulate this in [[FlightGear]], '''models must be animated'''.&lt;br /&gt;
&lt;br /&gt;
This document provides basic information for all kind of animations. For more complex animations, you are advised to check the available [[aircraft]] for examples.&lt;br /&gt;
&lt;br /&gt;
== A note about animation order ==&lt;br /&gt;
{{stub}}&lt;br /&gt;
&lt;br /&gt;
Animations are executed by FlightGear in the order that they are read in the model's .xml file. Therefore, it is very important to pay attention to the order, especially when multiple animations are applied to the same object(s).&lt;br /&gt;
&lt;br /&gt;
== Special code parts ==&lt;br /&gt;
=== Axis ===&lt;br /&gt;
An axis part is required in every animation that involves a rotating or moving thing.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
  &amp;lt;axis&amp;gt;&lt;br /&gt;
   &amp;lt;x&amp;gt;0&amp;lt;/x&amp;gt;&lt;br /&gt;
   &amp;lt;y&amp;gt;1&amp;lt;/y&amp;gt;&lt;br /&gt;
   &amp;lt;z&amp;gt;0&amp;lt;/z&amp;gt;&lt;br /&gt;
  &amp;lt;/axis&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The axis are similar to the ones of the 3D model. There is a difference between rotation and translation:&lt;br /&gt;
* In rotation animations, the axis part defines around what axis the object rotates. Negative/positive values make the difference between counterclockwise and clockwise rotations.&lt;br /&gt;
* In translate animations, the part defines along what axis the object moves. If the x-axis is poiting backwards, an x-value of -1 will result in forward motion.&lt;br /&gt;
&lt;br /&gt;
You could also define two points, between which FlightGear will calculate the correct axis. This makes the use of a [[#Center|&amp;lt;nowiki&amp;gt;&amp;lt;center&amp;gt;&amp;lt;/nowiki&amp;gt;]] tag redundant! Such coordinates are extremely useful for animating control surfaces (rudder, elevators etc.).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
  &amp;lt;axis&amp;gt;   &lt;br /&gt;
   &amp;lt;x1-m&amp;gt; 4.9&amp;lt;/x1-m&amp;gt;&lt;br /&gt;
   &amp;lt;y1-m&amp;gt; 7.1&amp;lt;/y1-m&amp;gt;&lt;br /&gt;
   &amp;lt;z1-m&amp;gt;-1.0&amp;lt;/z1-m&amp;gt;&lt;br /&gt;
   &amp;lt;x2-m&amp;gt; 5.9&amp;lt;/x2-m&amp;gt;&lt;br /&gt;
   &amp;lt;y2-m&amp;gt;11.2&amp;lt;/y2-m&amp;gt;&lt;br /&gt;
   &amp;lt;z2-m&amp;gt;-0.5&amp;lt;/z2-m&amp;gt;&lt;br /&gt;
  &amp;lt;/axis&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Center ===&lt;br /&gt;
Various animations ([[#Rotate|rotate]], [[#Spin|spin]]) move around a center point.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
  &amp;lt;center&amp;gt;&lt;br /&gt;
   &amp;lt;x-m&amp;gt;-1.50&amp;lt;/x-m&amp;gt;&lt;br /&gt;
   &amp;lt;y-m&amp;gt; 1   &amp;lt;/y-m&amp;gt;&lt;br /&gt;
   &amp;lt;z-m&amp;gt; 0.25&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  &amp;lt;/center&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The axis are similar to the ones of the 3D model, so finding coordinates is easily done in 3D modeling software.&lt;br /&gt;
&lt;br /&gt;
=== Conditions ===&lt;br /&gt;
Multiple animations can make use of a conditional. Check &amp;lt;tt&amp;gt;$FGDATA/Docs/README.conditions&amp;lt;/tt&amp;gt; for some more details.&lt;br /&gt;
&lt;br /&gt;
* '''equals:''' property value (or second property) is equal to value/(first)property.&lt;br /&gt;
* '''greater-than:''' property value (or second property) is larger than value/(first)property.&lt;br /&gt;
* '''greater-than-equals:''' property value (or second property) is greater than or equal to value/(first)property.&lt;br /&gt;
* '''less-than:''' property value (or second property) is smaller than value/(first)property.&lt;br /&gt;
* '''less-than-equals:''' property value (or second property) is smaller than or equal to value/(first)property.&lt;br /&gt;
&lt;br /&gt;
The example below is true when n1 has a value greater than 25.&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
  &amp;lt;condition&amp;gt;&lt;br /&gt;
   &amp;lt;greater-than&amp;gt;&lt;br /&gt;
    &amp;lt;property&amp;gt;engines/engine[1]/n1&amp;lt;/property&amp;gt;&lt;br /&gt;
    &amp;lt;value&amp;gt;25&amp;lt;/value&amp;gt;&lt;br /&gt;
   &amp;lt;/greater-than&amp;gt;&lt;br /&gt;
  &amp;lt;/condition&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then there are some special tags:&lt;br /&gt;
&lt;br /&gt;
* '''and:'''&lt;br /&gt;
* '''not:'''&lt;br /&gt;
* '''or:'''&lt;br /&gt;
&lt;br /&gt;
In the example below, the condition is true when either n1 is greater than 25% or equal to 0%.&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
  &amp;lt;condition&amp;gt;&lt;br /&gt;
   &amp;lt;or&amp;gt;&lt;br /&gt;
    &amp;lt;greater-than&amp;gt;&lt;br /&gt;
     &amp;lt;property&amp;gt;engines/engine[1]/n1&amp;lt;/property&amp;gt;&lt;br /&gt;
     &amp;lt;value&amp;gt;25&amp;lt;/value&amp;gt;&lt;br /&gt;
    &amp;lt;/greater-than&amp;gt;&lt;br /&gt;
    &amp;lt;equals&amp;gt;&lt;br /&gt;
     &amp;lt;property&amp;gt;engines/engine[1]/n1&amp;lt;/property&amp;gt;&lt;br /&gt;
     &amp;lt;value&amp;gt;0&amp;lt;/value&amp;gt;&lt;br /&gt;
    &amp;lt;/equals&amp;gt;&lt;br /&gt;
   &amp;lt;/or&amp;gt;&lt;br /&gt;
  &amp;lt;/condition&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
An example of implementation into an animation looks as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;rotate&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;property&amp;gt;suface-positions/left-aileron-pos-norm&amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;factor&amp;gt;25&amp;lt;/factor&amp;gt;&lt;br /&gt;
  &amp;lt;condition&amp;gt;&lt;br /&gt;
   &amp;lt;greater-than&amp;gt;&lt;br /&gt;
    &amp;lt;property&amp;gt;suface-positions/left-aileron-pos-norm&amp;lt;/property&amp;gt;&lt;br /&gt;
    &amp;lt;value&amp;gt;10&amp;lt;/value&amp;gt;&lt;br /&gt;
   &amp;lt;/greater-than&amp;gt;&lt;br /&gt;
  &amp;lt;/condition&amp;gt;&lt;br /&gt;
  &amp;lt;center&amp;gt;&lt;br /&gt;
   &amp;lt;x-m&amp;gt;-1.50&amp;lt;/x-m&amp;gt;&lt;br /&gt;
   &amp;lt;y-m&amp;gt; 1   &amp;lt;/y-m&amp;gt;&lt;br /&gt;
   &amp;lt;z-m&amp;gt; 0.25&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  &amp;lt;/center&amp;gt;&lt;br /&gt;
  &amp;lt;axis&amp;gt;&lt;br /&gt;
   &amp;lt;x&amp;gt;0&amp;lt;/x&amp;gt;&lt;br /&gt;
   &amp;lt;y&amp;gt;1&amp;lt;/y&amp;gt;&lt;br /&gt;
   &amp;lt;z&amp;gt;0&amp;lt;/z&amp;gt;&lt;br /&gt;
  &amp;lt;/axis&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Interpolation ===&lt;br /&gt;
For non-fixed factors, an interpolation &amp;quot;table&amp;quot; can be created. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
  &amp;lt;interpolation&amp;gt;&lt;br /&gt;
   &amp;lt;entry&amp;gt;&lt;br /&gt;
    &amp;lt;ind&amp;gt; 0.0&amp;lt;/ind&amp;gt;&lt;br /&gt;
    &amp;lt;dep&amp;gt; 0.0&amp;lt;/dep&amp;gt;&lt;br /&gt;
   &amp;lt;/entry&amp;gt;&lt;br /&gt;
   &amp;lt;entry&amp;gt;&lt;br /&gt;
    &amp;lt;ind&amp;gt; 0.667&amp;lt;/ind&amp;gt;&lt;br /&gt;
    &amp;lt;dep&amp;gt; 0.0&amp;lt;/dep&amp;gt;&lt;br /&gt;
   &amp;lt;/entry&amp;gt;&lt;br /&gt;
   &amp;lt;entry&amp;gt;&lt;br /&gt;
    &amp;lt;ind&amp;gt; 1.0&amp;lt;/ind&amp;gt;&lt;br /&gt;
    &amp;lt;dep&amp;gt; 0.5&amp;lt;/dep&amp;gt;&lt;br /&gt;
   &amp;lt;/entry&amp;gt;&lt;br /&gt;
  &amp;lt;/interpolation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The lines above represent the following table:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
!Input&lt;br /&gt;
!Output&lt;br /&gt;
|-&lt;br /&gt;
|0.0&lt;br /&gt;
|0.0&lt;br /&gt;
|-&lt;br /&gt;
|0.667&lt;br /&gt;
|0.0&lt;br /&gt;
|-&lt;br /&gt;
|1.0&lt;br /&gt;
|0.5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
You can add as many entries as you need. Interpolation tables are often used for gear animations (eg. to open doors during gear-movements and close them again once the gear is either retracted or fully extended).&lt;br /&gt;
&lt;br /&gt;
=== Name ===&lt;br /&gt;
With a name animation, you can group multiple objects. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;name&amp;gt;Collection1&amp;lt;/name&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object1&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object2&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object3&amp;lt;/object-name&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The example above creates a &amp;quot;virtual object&amp;quot; with the name Collection1. In animation, we can animate this group of objects, by using:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;object-name&amp;gt;Collection1&amp;lt;/object-name&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Object-name ===&lt;br /&gt;
These names are set in the 3D model. Each single object has a unique name; for easy identification it is advised to use descriptive names (LeftElevator, Rudder etc.). Animations are only applied to those objects that are mentioned in an object-name line (one object per line!). Animations lacking those, will be applied to the entire model.&lt;br /&gt;
&lt;br /&gt;
== Animation types ==&lt;br /&gt;
=== Alpha-test ===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;alpha-test&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;alpha-factor&amp;gt;0.01&amp;lt;/alpha-factor&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Billboard ===&lt;br /&gt;
This faces an object towards the viewer. Often used on 2D objects, like clouds, trees and lights.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;billboard&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;spherical type=&amp;quot;bool&amp;quot;&amp;gt;true&amp;lt;/spherical&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''spherical:'''&lt;br /&gt;
&lt;br /&gt;
=== Dist-scale ===&lt;br /&gt;
Used to scale an object, based on the distance to the viewer.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;dist-scale&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;interpolation&amp;gt;&lt;br /&gt;
   &amp;lt;entry&amp;gt;&lt;br /&gt;
    &amp;lt;ind&amp;gt;0&amp;lt;/ind&amp;gt;&lt;br /&gt;
    &amp;lt;dep&amp;gt;1&amp;lt;/dep&amp;gt;&lt;br /&gt;
   &amp;lt;/entry&amp;gt;&lt;br /&gt;
   &amp;lt;entry&amp;gt;&lt;br /&gt;
    &amp;lt;ind&amp;gt;300&amp;lt;/ind&amp;gt;&lt;br /&gt;
    &amp;lt;dep&amp;gt;4&amp;lt;/dep&amp;gt;&lt;br /&gt;
   &amp;lt;/entry&amp;gt;&lt;br /&gt;
   &amp;lt;entry&amp;gt;&lt;br /&gt;
    &amp;lt;ind&amp;gt;1500&amp;lt;/ind&amp;gt;&lt;br /&gt;
    &amp;lt;dep&amp;gt;8&amp;lt;/dep&amp;gt;&lt;br /&gt;
   &amp;lt;/entry&amp;gt;&lt;br /&gt;
  &amp;lt;/interpolation&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Enable-hot ===&lt;br /&gt;
Scenery objects are automatically defined as solid by FlightGear, meaning that an aircraft can taxi on them and/or crash when touching. For certain objects (groundmarkings, beacon light-beams etc.) this might be an unwanted feature. The solidness can be disabled with the following animation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;enable-hot type=&amp;quot;bool&amp;quot;&amp;gt;false&amp;lt;/enable-hot&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''enable-hot:''' can be either true or false. Remember that objects are automatically solid, so it should not be nesecarily to set this at all when wanting solidness.&lt;br /&gt;
&lt;br /&gt;
=== Flash ===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;flash&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;offset&amp;gt;0.0&amp;lt;/offset&amp;gt;&lt;br /&gt;
  &amp;lt;factor&amp;gt;1.0&amp;lt;/factor&amp;gt;&lt;br /&gt;
  &amp;lt;power&amp;gt;2&amp;lt;/power&amp;gt;&lt;br /&gt;
  &amp;lt;two-sides type=&amp;quot;bool&amp;quot;&amp;gt;false&amp;lt;/two-sides&amp;gt;&lt;br /&gt;
  &amp;lt;min&amp;gt;0.0&amp;lt;/min&amp;gt;&lt;br /&gt;
  &amp;lt;max&amp;gt;1.0&amp;lt;/max&amp;gt;&lt;br /&gt;
  &amp;lt;center&amp;gt;&lt;br /&gt;
   &amp;lt;x-m&amp;gt;0.0&amp;lt;/x-m&amp;gt;&lt;br /&gt;
   &amp;lt;y-m&amp;gt;0.0&amp;lt;/y-m&amp;gt;&lt;br /&gt;
   &amp;lt;z-m&amp;gt;0.0&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  &amp;lt;/center&amp;gt;&lt;br /&gt;
  &amp;lt;axis&amp;gt;&lt;br /&gt;
   &amp;lt;x&amp;gt;0.0&amp;lt;/x&amp;gt;&lt;br /&gt;
   &amp;lt;y&amp;gt;-1&amp;lt;/y&amp;gt;&lt;br /&gt;
   &amp;lt;z&amp;gt;0.1&amp;lt;/z&amp;gt;&lt;br /&gt;
  &amp;lt;/axis&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''offset:'''&lt;br /&gt;
* '''factor:'''&lt;br /&gt;
* '''power:'''&lt;br /&gt;
* '''two-sides:'''&lt;br /&gt;
* '''min:'''&lt;br /&gt;
* '''max:'''&lt;br /&gt;
&lt;br /&gt;
=== Interactions ===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt; &lt;br /&gt;
  &amp;lt;type&amp;gt;interaction&amp;lt;/type&amp;gt; &lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt; &lt;br /&gt;
  &amp;lt;interaction-type&amp;gt;carrier-wire&amp;lt;/interaction-type&amp;gt; &lt;br /&gt;
 &amp;lt;/animation&amp;gt; &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''interaction-type:''' can have the following values:&lt;br /&gt;
** '''carrier-catapult:'''&lt;br /&gt;
** '''carrier-wire:''' makes the object act as an arresting wire, as used on [[aircraft carrier]]s.&lt;br /&gt;
&lt;br /&gt;
=== Material ===&lt;br /&gt;
An animation type that can be used in various ways. Of course you can combine the below mentiond systems into one (big) animation.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt; &lt;br /&gt;
  &amp;lt;type&amp;gt;material&amp;lt;/type&amp;gt; &lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;property-base&amp;gt;sim/model/c172p/material&amp;lt;/property-base&amp;gt;&lt;br /&gt;
  &amp;lt;global type=&amp;quot;bool&amp;quot;&amp;gt;true&amp;lt;/global&amp;gt;&lt;br /&gt;
  ...&lt;br /&gt;
  lines as mentioned below&lt;br /&gt;
  ...&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Optional:'''&lt;br /&gt;
* '''property-base:''' when using prop(erties), you might want to set a property-base. All props will be relative to this path.&lt;br /&gt;
* '''global:''' by setting this to &amp;lt;tt&amp;gt;true&amp;lt;/tt&amp;gt;, all objects using the same material as the defined object(s) (via &amp;lt;tt&amp;gt;&amp;lt;object-name&amp;gt;&amp;lt;/tt&amp;gt;) will be affected by the animation. This is preferred to listing several objects in &amp;lt;object-name&amp;gt; tags. It's not only faster, but also doesn't break animations by forcing objects together.&lt;br /&gt;
&lt;br /&gt;
'''Notes:'''&lt;br /&gt;
* Numbers are clamped to 0.0-1.0, except &amp;quot;shininess&amp;quot;, which is clamped to 0-128.&lt;br /&gt;
* By appending &amp;lt;tt&amp;gt;-prop&amp;lt;/tt&amp;gt; each of the material properties can read its value from another property.&lt;br /&gt;
&lt;br /&gt;
==== Ambient ====&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
  &amp;lt;ambient&amp;gt;&lt;br /&gt;
   &amp;lt;red&amp;gt;1.0&amp;lt;/red&amp;gt;&lt;br /&gt;
   &amp;lt;green&amp;gt;0.2&amp;lt;/green&amp;gt;&lt;br /&gt;
   &amp;lt;blue&amp;gt;0.0&amp;lt;/blue&amp;gt;&lt;br /&gt;
  &amp;lt;/ambient&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Diffuse ====&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
  &amp;lt;diffuse&amp;gt;&lt;br /&gt;
   &amp;lt;red&amp;gt;1.0&amp;lt;/red&amp;gt;&lt;br /&gt;
   &amp;lt;green&amp;gt;0.2&amp;lt;/green&amp;gt;&lt;br /&gt;
   &amp;lt;blue&amp;gt;0.0&amp;lt;/blue&amp;gt;&lt;br /&gt;
  &amp;lt;/diffuse&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Emission ====&lt;br /&gt;
{{Main article|Howto: Illuminate faces}}&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
  &amp;lt;emission&amp;gt;&lt;br /&gt;
   &amp;lt;red&amp;gt;1.0&amp;lt;/red&amp;gt;&lt;br /&gt;
   &amp;lt;green&amp;gt;0.2&amp;lt;/green&amp;gt;&lt;br /&gt;
   &amp;lt;blue&amp;gt;0.0&amp;lt;/blue&amp;gt;&lt;br /&gt;
   &amp;lt;factor-prop&amp;gt;controls/lighting/panel-norm&amp;lt;/factor-prop&amp;gt;&lt;br /&gt;
  &amp;lt;/emission&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Emission colors are multiplied by the factor-prop value. 1 is maximum coclor intensity, while 0 is the minimum. Colors are calculated according to the [http://en.wikipedia.org/wiki/RGB_color_model RGB color model].&lt;br /&gt;
&lt;br /&gt;
==== Shininess ====&lt;br /&gt;
Shininess is clamped to 0-128.&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
  &amp;lt;shininess&amp;gt;105&amp;lt;/shininess&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Specular ====&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
  &amp;lt;specular&amp;gt;&lt;br /&gt;
   &amp;lt;red&amp;gt;1.0&amp;lt;/red&amp;gt;&lt;br /&gt;
   &amp;lt;green&amp;gt;0.2&amp;lt;/green&amp;gt;&lt;br /&gt;
   &amp;lt;blue&amp;gt;0.0&amp;lt;/blue&amp;gt;&lt;br /&gt;
  &amp;lt;/specular&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Texture ====&lt;br /&gt;
Used for the [[Livery over MP]] system.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
  &amp;lt;property-base&amp;gt;sim/model/livery&amp;lt;/property-base&amp;gt; &lt;br /&gt;
  &amp;lt;texture-prop&amp;gt;engine&amp;lt;/texture-prop&amp;gt; &lt;br /&gt;
  &amp;lt;texture&amp;gt;KLM.png&amp;lt;/texture&amp;gt; &lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Transparency ====&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
  &amp;lt;transparency&amp;gt;&lt;br /&gt;
   &amp;lt;alpha-prop&amp;gt;rotors/tail/rpm&amp;lt;/alpha-prop&amp;gt;&lt;br /&gt;
   &amp;lt;factor&amp;gt;-0.0015&amp;lt;/factor&amp;gt;&lt;br /&gt;
   &amp;lt;offset&amp;gt;1&amp;lt;/offset&amp;gt;&lt;br /&gt;
  &amp;lt;/transparency&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Threshold ====&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
  &amp;lt;threshold&amp;gt;0.001&amp;lt;/threshold&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Noshadow ===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;noshadow&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Pick ===&lt;br /&gt;
{{Main article|Howto: Make a clickable panel#Pick}}&lt;br /&gt;
&lt;br /&gt;
=== Range ===&lt;br /&gt;
To prevent objects -like instruments- being drawn when the aircraft is actually too far away for them to be seen anyway, a range animation is used. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;range&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;min-m&amp;gt;0&amp;lt;/min-m&amp;gt;&lt;br /&gt;
  &amp;lt;max-m&amp;gt;30&amp;lt;/max-m&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''min-m:''' the shortest distance (in meters) from the object center at which it is visible.&lt;br /&gt;
* '''max-m:''' the largest distance (in meters) from the object center at which it is visible.&lt;br /&gt;
&lt;br /&gt;
You could also use the generic level of detail (LOD) properties, which can be set by the user through View &amp;gt; Adjust LOD rangers: &lt;br /&gt;
* &amp;lt;tt&amp;gt;/sim/rendering/static-lod/bare&amp;lt;/tt&amp;gt; distance at which only a rough exterior model is required.&lt;br /&gt;
* &amp;lt;tt&amp;gt;/sim/rendering/static-lod/rough&amp;lt;/tt&amp;gt; distance at which most should be visible.&lt;br /&gt;
* &amp;lt;tt&amp;gt;/sim/rendering/static-lod/detailed&amp;lt;/tt&amp;gt; distance at which all details should be visible.&lt;br /&gt;
&lt;br /&gt;
The animation code will look like this:&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;range&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;min-m&amp;gt;0&amp;lt;/min-m&amp;gt;&lt;br /&gt;
  &amp;lt;max-property&amp;gt;sim/rendering/static-lod/bare&amp;lt;/max-property&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can have both ranges (max and min) bound to a property, or just one of them.&lt;br /&gt;
* '''min-property:''' &lt;br /&gt;
* '''max-property:'''&lt;br /&gt;
&lt;br /&gt;
=== Rotate ===&lt;br /&gt;
One of the most important and frequently used animations of all. It rotates an object to an absolute position in degrees, as provided by the property-value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;rotate&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;property&amp;gt;suface-positions/left-aileron-pos-norm&amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;factor&amp;gt;25&amp;lt;/factor&amp;gt;&lt;br /&gt;
  &amp;lt;center&amp;gt;&lt;br /&gt;
   &amp;lt;x-m&amp;gt;-1.50&amp;lt;/x-m&amp;gt;&lt;br /&gt;
   &amp;lt;y-m&amp;gt; 1   &amp;lt;/y-m&amp;gt;&lt;br /&gt;
   &amp;lt;z-m&amp;gt; 0.25&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  &amp;lt;/center&amp;gt;&lt;br /&gt;
  &amp;lt;axis&amp;gt;&lt;br /&gt;
   &amp;lt;x&amp;gt;0&amp;lt;/x&amp;gt;&lt;br /&gt;
   &amp;lt;y&amp;gt;1&amp;lt;/y&amp;gt;&lt;br /&gt;
   &amp;lt;z&amp;gt;0&amp;lt;/z&amp;gt;&lt;br /&gt;
  &amp;lt;/axis&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''factor:''' is optional.&lt;br /&gt;
&lt;br /&gt;
=== Scale ===&lt;br /&gt;
A scale animation scales (resizes) an object. This can be either property-value dependant (first example) or a fixed scale (second example).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;scale&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;property&amp;gt;sim/time/sun-angle-rad&amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;x-min&amp;gt;1.0&amp;lt;/x-min&amp;gt;&lt;br /&gt;
  &amp;lt;y-min&amp;gt;1.0&amp;lt;/y-min&amp;gt;&lt;br /&gt;
  &amp;lt;z-min&amp;gt;1.0&amp;lt;/z-min&amp;gt;&lt;br /&gt;
  &amp;lt;x-factor&amp;gt;1.4&amp;lt;/x-factor&amp;gt;&lt;br /&gt;
  &amp;lt;y-factor&amp;gt;1.4&amp;lt;/y-factor&amp;gt;&lt;br /&gt;
  &amp;lt;z-factor&amp;gt;2.0&amp;lt;/z-factor&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* ?-min: the mimimum scale factor for each axis. If the property value would result in a smaller factor than this setting, the scale animation will hold.&lt;br /&gt;
* ?-factor: the scale factor for each axis (factor*property=scale factor).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;scale&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;x-offset&amp;gt;0.5&amp;lt;/x-offset&amp;gt;&lt;br /&gt;
  &amp;lt;y-offset&amp;gt;0.5&amp;lt;/y-offset&amp;gt;&lt;br /&gt;
  &amp;lt;z-offset&amp;gt;0.5&amp;lt;/z-offset&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* x.offset: the scale factor.&lt;br /&gt;
&lt;br /&gt;
=== Select ===&lt;br /&gt;
This animation selects (or unselects) objects when certain conditions are true (or false). The example below shows the object when the n1 of engine[1] is higher than 25%.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;select&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;condition&amp;gt;&lt;br /&gt;
   &amp;lt;greater-than&amp;gt;&lt;br /&gt;
    &amp;lt;property&amp;gt;engines/engine[0]/n1&amp;lt;/property&amp;gt;&lt;br /&gt;
    &amp;lt;value&amp;gt;25&amp;lt;/value&amp;gt;&lt;br /&gt;
   &amp;lt;/greater-than&amp;gt;&lt;br /&gt;
  &amp;lt;/condition&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Shader ===&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;shader&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;shader&amp;gt;chrome&amp;lt;/shader&amp;gt;&lt;br /&gt;
  &amp;lt;texture&amp;gt;chrome2.png&amp;lt;/texture&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''shader:''' &lt;br /&gt;
* '''texture:''' path to the texture used by the shader.&lt;br /&gt;
&lt;br /&gt;
=== Spin ===&lt;br /&gt;
Very similar to [[#Rotate|rotate]], but the property provides a value in revolutions per minute (RPM) rather than an absolute position in degrees, and offset cannot be used.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;spin&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;property&amp;gt;engines/engine[0]/n1&amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;factor&amp;gt;25&amp;lt;/factor&amp;gt;&lt;br /&gt;
  &amp;lt;center&amp;gt;&lt;br /&gt;
   &amp;lt;x-m&amp;gt;-1.50&amp;lt;/x-m&amp;gt;&lt;br /&gt;
   &amp;lt;y-m&amp;gt; 1   &amp;lt;/y-m&amp;gt;&lt;br /&gt;
   &amp;lt;z-m&amp;gt; 0.25&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  &amp;lt;/center&amp;gt;&lt;br /&gt;
  &amp;lt;axis&amp;gt;&lt;br /&gt;
   &amp;lt;x&amp;gt;0&amp;lt;/x&amp;gt;&lt;br /&gt;
   &amp;lt;y&amp;gt;1&amp;lt;/y&amp;gt;&lt;br /&gt;
   &amp;lt;z&amp;gt;0&amp;lt;/z&amp;gt;&lt;br /&gt;
  &amp;lt;/axis&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''factor:''' is optional.&lt;br /&gt;
&lt;br /&gt;
=== Textranslate ===&lt;br /&gt;
A very important animation for cockpits! This animation moves textures over a surface.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;textranslate&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;property&amp;gt;autopilot/settings/target-speed-kt&amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;factor&amp;gt;0.001&amp;lt;/factor&amp;gt;&lt;br /&gt;
  &amp;lt;step&amp;gt;100&amp;lt;/step&amp;gt;&lt;br /&gt;
  &amp;lt;axis&amp;gt;&lt;br /&gt;
   &amp;lt;x&amp;gt;0&amp;lt;/x&amp;gt;&lt;br /&gt;
   &amp;lt;y&amp;gt;1&amp;lt;/y&amp;gt;&lt;br /&gt;
   &amp;lt;z&amp;gt;0&amp;lt;/z&amp;gt;&lt;br /&gt;
  &amp;lt;/axis&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* '''factor:'''&lt;br /&gt;
* '''step:'''&lt;br /&gt;
property * factor * step * texture width/height = the amount of pixels that the texture should be translated. If your texture is 256 pixels, an textranslate of 0.1 will result in the texture moving with 26 pixels, into the direction specified by the axis settings.&lt;br /&gt;
&lt;br /&gt;
=== Timed ===&lt;br /&gt;
Swtiches between objects at specified intervals. This example switches between a lights-on model and a lights-off model. Lights on are shown 0.2 seconds, while lights off are displayed for 0.8 seconds.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;timed&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;BacklightOn&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;BacklightOff&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;use-personality type=&amp;quot;bool&amp;quot;&amp;gt;true&amp;lt;/use-personality&amp;gt;&lt;br /&gt;
  &amp;lt;branch-duration-sec&amp;gt;0.8&amp;lt;/branch-duration-sec&amp;gt;&lt;br /&gt;
  &amp;lt;branch-duration-sec&amp;gt;0.2&amp;lt;/branch-duration-sec&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Translate ===&lt;br /&gt;
The same as [[#Textranslate|textranslate]], but this animation moves a whole object (so including fixed textures). The example below will move an object 5 meters in the y-direction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;source&amp;gt;&lt;br /&gt;
 &amp;lt;animation&amp;gt;&lt;br /&gt;
  &amp;lt;type&amp;gt;translate&amp;lt;/type&amp;gt;&lt;br /&gt;
  &amp;lt;object-name&amp;gt;Object&amp;lt;/object-name&amp;gt;&lt;br /&gt;
  &amp;lt;property&amp;gt;controls/seat/pilot/position-norm&amp;lt;/property&amp;gt;&lt;br /&gt;
  &amp;lt;factor&amp;gt;5&amp;lt;/factor&amp;gt;&lt;br /&gt;
  &amp;lt;axis&amp;gt;&lt;br /&gt;
   &amp;lt;x&amp;gt;0&amp;lt;/x&amp;gt;&lt;br /&gt;
   &amp;lt;y&amp;gt;1&amp;lt;/y&amp;gt;&lt;br /&gt;
   &amp;lt;z&amp;gt;0&amp;lt;/z&amp;gt;&lt;br /&gt;
  &amp;lt;/axis&amp;gt;&lt;br /&gt;
 &amp;lt;/animation&amp;gt;&lt;br /&gt;
&amp;lt;/source&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* [http://www.opensubscriber.com/message/flightgear-devel@flightgear.org/958955.html &amp;quot;material&amp;quot; animation (and the bo105 as an example)]&lt;br /&gt;
by Melchior Fanz, March 22 2005.&lt;br /&gt;
&lt;br /&gt;
[[Category:Aircraft enhancement|Animate models]]&lt;br /&gt;
[[Category:Howto|Animate models]]&lt;br /&gt;
[[Category:Modeling|Animate models]]&lt;br /&gt;
[[Category:Scenery enhancement|Animate models]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30899</id>
		<title>Howto:Coding a Boeing CDU</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30899"/>
		<updated>2011-04-08T21:05:53Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Examples */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
[[User:Gijs|Gijs]] has started an effort to bring a generic Boeing [[CDU]] to [[FlightGear]]. This page tries to describe the coding for this effort.&lt;br /&gt;
&lt;br /&gt;
= The Sources =&lt;br /&gt;
The [[CDU]] currently resides in '''$FGDATA/Aircraft/Instruments-3d/cdu/'''.&lt;br /&gt;
&lt;br /&gt;
'''Graphics''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.ac&amp;lt;/tt&amp;gt;: This is a [[AC3D]] file, describing the 3D outline of the CDU model.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_brown.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_grey.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
&lt;br /&gt;
'''XML''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;: This is the main [[XML]] file, providing the direct interface between the 3D model and the code. This file also defines the keypress interactions and the positioning of the text to be displayed in the screen.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display-matrix-text.xml&amp;lt;/tt&amp;gt;: An OSGText &amp;quot;model&amp;quot;, used as a baseline for the texts on the screen. Compare to &amp;lt;tt&amp;gt;README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Nasal''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;: This is the main [[Nasal]] script file to be edited by the ''user'' of the CDU Nasal framework.&lt;br /&gt;
* &amp;lt;tt&amp;gt;cdu_page_framework.nas&amp;lt;/tt&amp;gt;: This is the main file of the CDU framework. It defines the main ''classes'' used for the CDU.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;: This file contains the Nasal relevant for the dispaly matrix. This code might be useful for other complex screen-based instruments.&lt;br /&gt;
* &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;: This file contains functions which I found useful for my project, but which are totally generic and could be used for other stuff as well.&lt;br /&gt;
* &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;: This file contains a rudimentary timer ''class'' and an example of how to incorporate this with a generic class for an instrument button, allowing the button to call different Nasal scripts, depending on how long it has been pressed. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;README&amp;lt;/tt&amp;gt;: Well, a readme.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Loading a CDU into an Aircraft ==&lt;br /&gt;
Here is how the CDU is loaded into the Boeing 777-200:&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;777-22ER-set.xml&amp;lt;/tt&amp;gt; the Nasal node is expanded as follows:&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- generic for the CDU --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/helping_functions.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/timer.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/cdu_page_framework.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;nowiki&amp;gt;&amp;lt;!-- specific for the B777 --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/b777_cdu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
Note the difference in the framework files and the actual ''instance'' used for this aircraft. To code pages for the CDU, one would normally not have to mess with the framework files. [[User:Hcc23|Hcc23]]&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Somewhere in the actual 3D model of the aircraft the &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; for the 3D model of the CDU has to be loaded. I haven't looked for that yet as that was already done for the 777-200. [[User:Hcc23|Hcc23]] 14:42, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== 3D Graphics ==&lt;br /&gt;
The 3D model resides in the file '''&amp;lt;tt&amp;gt;$FGDATA/Models/Cockpit/Instruments/CDU/cdu.ac&amp;lt;/tt&amp;gt;'''. This is a [[AC3D]] file format, but it should be importable by [[Blender]].&lt;br /&gt;
{|&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| [[File:CDU_3D_wireframe.png|thumb|270px|The wireframe of the 3D model and the corresponding coordinate system. ATTENTION: the axis are not right: RED is +X, GREEN is +Z, BLUE is -Y !]]&lt;br /&gt;
| [[File:CDU.png|thumb|270px|The texture of the CDU, a 512x512 PNG bitmap.]]&lt;br /&gt;
| [[File:CDU_3D_textures.png|thumb|270px|The resulting 3D model, after the textures have been added.]]&lt;br /&gt;
|}&lt;br /&gt;
The model also specifies the model internal coordinate system. It is indicated in the pictures through the corresponding axis: X (red), Y (green), and Z (blue). The origin of this coordinate system seems to coincide with the geometric center of the back plane of the [[CDU]], i.e. the YZ-plane is coplanar with the back of the [[CDU]]. The unit of the coordinate system is the SI unit ''Meter''.&lt;br /&gt;
&lt;br /&gt;
The 3D model has bindings defined to each button. So when a certain button is clicked, something happens. Right now most buttons are only used&lt;br /&gt;
to open other [[CDU]]-pages.&lt;br /&gt;
&lt;br /&gt;
=== The Screen of the CDU ===&lt;br /&gt;
With respect to the model coordinate frame, the screen is the rectangle given by:&lt;br /&gt;
&lt;br /&gt;
  Top edge:   z= 0.111, x=0.004&lt;br /&gt;
  Lower edge: z= 0.019, x=0.004&lt;br /&gt;
  Left edge:  y=-0.051, x=0.004&lt;br /&gt;
  Right edge: y= 0.051, x=0.004&lt;br /&gt;
&lt;br /&gt;
= The Code Framework =&lt;br /&gt;
&lt;br /&gt;
The CDU framework is implemented following some classic object-oriented ideas, completely implemented in Nasal. All variables are instanciated using &amp;lt;tt&amp;gt;var&amp;lt;/tt&amp;gt; so that the global namespace should not be tainted.&lt;br /&gt;
&lt;br /&gt;
The idea for the framework stems from the fact that a CDU is based upon the idea of ''pages'', some of which could occupy several screens. This, in conjunction with the idea of the ''fields'' (stipulated from the screen layout of the CDU) resulted in the following framework:&lt;br /&gt;
  CDU&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | | &lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | |&lt;br /&gt;
  | |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  |   |&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-...&lt;br /&gt;
Well, you get the idea....&lt;br /&gt;
&lt;br /&gt;
These three ''classes'' (BasePage, SubPage, Field) are defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;. The constructors are generally called &amp;lt;tt&amp;gt;.new()&amp;lt;/tt&amp;gt;, all ''memberss'' are created within the constructors, all ''static'' parts are implemented directly on the hash level.&lt;br /&gt;
&lt;br /&gt;
Beside these three classes the class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;) is used to house the actual text to be printed.&lt;br /&gt;
&lt;br /&gt;
All text is then kept internal to Nasal within the beforementioned structure. The text is then also kept in the FlightGear property tree so that an interface to osgtext can be established via &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' There is a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable set in the CDU framework. Setting this variable to non-zero enables a bunch of console printouts, implemented via &amp;lt;tt&amp;gt;DEBUG?print('....'):;&amp;lt;/tt&amp;gt; Furthermore, when calling a constructor, the parameter &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt; (for path-to-property) can be set, enabling some member variables of the classes to register themselves in the property tree, allowing an easier debugging during runtime. [[User:Hcc23|Hcc23]] 15:20, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
Maybe looking at the actual code is the easiest way of understanding how the framework works. (I also tried to be fairly explicit in my in-code comments, so looking at the sources should actually be helpful, too. [[User:Hcc23|Hcc23]] 15:46, 8 April 2011 (EDT))&lt;br /&gt;
&lt;br /&gt;
As the framework is separate from the ''instanciation'', let's focus on that as that is the part a ''user'' should care mostly about. The relevant file for the Boeing 777-200 is &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Preliminaries===&lt;br /&gt;
  #####################################################&lt;br /&gt;
  # These variables have already been defined in &lt;br /&gt;
  # cdu_page_framework but can (?) be redifined here &lt;br /&gt;
  # for slightly changed versions.&lt;br /&gt;
  #####################################################&lt;br /&gt;
  &lt;br /&gt;
  var ROWS = 14; 	# the number of lines the CDU has&lt;br /&gt;
  var COLS = 24; 	# the number of characters each line can hold&lt;br /&gt;
  var PROP = &amp;quot;/instrumentation/cdu&amp;quot;; 	# generic path to the properties of this CDU&lt;br /&gt;
  var DEBUG = 1; # enable a more verbose &amp;quot;debug&amp;quot; mode, i.e. register all kinds of stuff in the property tree&lt;br /&gt;
  &lt;br /&gt;
  resetDisplayMatrix();&lt;br /&gt;
This essential defines the size of the dispaly matrix, enables the debug printout and clears the display matrix in the property tree.&lt;br /&gt;
(&amp;lt;tt&amp;gt;resetDisplayMatrix();&amp;lt;/tt&amp;gt; fills the complete display matrix with spaces ( ) and also set the style to &amp;lt;tt&amp;gt;&amp;quot;off&amp;quot;&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
===Making the BasePages===&lt;br /&gt;
  # make the pages&lt;br /&gt;
  var page_menu      = BasePage.new(&amp;quot;MENU&amp;quot;,PROP~&amp;quot;/page_menu&amp;quot;); &lt;br /&gt;
  KeyBinding[&amp;quot;MENU&amp;quot;] = func() {page_menu.displayPage(); }; # Note : do NOT forget to wrap displayPage with a function!&lt;br /&gt;
  var page_index     = BasePage.new(&amp;quot;INDEX&amp;quot;,PROP~&amp;quot;/page_index&amp;quot;); &lt;br /&gt;
  var page_ident     = BasePage.new(&amp;quot;IDENT&amp;quot;,PROP~&amp;quot;/page_ident&amp;quot;); &lt;br /&gt;
  var page_pos       = BasePage.new(&amp;quot;POS&amp;quot;,PROP~&amp;quot;/page_pos&amp;quot;); &lt;br /&gt;
  var page_perf      = BasePage.new(&amp;quot;PERF&amp;quot;,PROP~&amp;quot;/page_perf&amp;quot;); &lt;br /&gt;
  var page_thrustLim = BasePage.new(&amp;quot;THRUST LIM&amp;quot;,PROP~&amp;quot;/page_thurstLim&amp;quot;); &lt;br /&gt;
  var page_takeoff   = BasePage.new(&amp;quot;TAKEOFF&amp;quot;,PROP~&amp;quot;/page_takeoff&amp;quot;); &lt;br /&gt;
  var page_approach  = BasePage.new(&amp;quot;APPROACH&amp;quot;,PROP~&amp;quot;/page_approach&amp;quot;); &lt;br /&gt;
  var page_navData   = BasePage.new(&amp;quot;NAV DATA&amp;quot;,PROP~&amp;quot;/page_navData&amp;quot;); &lt;br /&gt;
  var page_maint     = BasePage.new(&amp;quot;MAINT&amp;quot;,PROP~&amp;quot;/page_maint&amp;quot;); &lt;br /&gt;
This section creates the base pages of the CDU. The constructor for base pages is this one:&lt;br /&gt;
  new: func(name,ptp=nil) {...};&lt;br /&gt;
What this essentially does is creating a container to house sub pages. The &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element is used as the title of the page (but this could be overwritten in a sub page), the &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;, if set, registers the base page at that path. (However, if the &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable is set, the the pages are registered by their internal ID in a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; path underneath the CDU.)&lt;br /&gt;
&lt;br /&gt;
When a base page constructor is called, it also creates a ''home''-method. This function can be used to make the corresponding base page the active page, i.e. display that page. As you can see above, the corresponding method of the MENU page is assigned to the related button of the CDU. &amp;lt;tt&amp;gt;KeyBinding&amp;lt;/tt&amp;gt; is defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;, for a list of the available buttons see &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Making a SubPage (and the corresponding Fields)===&lt;br /&gt;
  #######################&lt;br /&gt;
  # DETAILS PAGE MENU&lt;br /&gt;
  #######################&lt;br /&gt;
  #&lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make details for page &amp;quot;~&amp;quot;MENU&amp;quot;):;&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_menu_default = SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,&amp;quot;FMC&amp;quot;,page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
  &lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_menu_default.activate();&lt;br /&gt;
This code section starts to fill in the details of the page MENU. As outlined in the framework, each base page houses sub pages, which in turn house the fields (which hold the actual content). So we need to start by making a sub page:&lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_menu_default = SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
The constructor for a sub page looks like this:&lt;br /&gt;
  new: func(parent_base_page,name=nil,ptp=nil) {...};&lt;br /&gt;
The elements are fairly straight forward:&lt;br /&gt;
* parent_base_page: parent node of this sub page (which is a base page). Note that this is not the name of that page, but the actual page, i.e. put down the name of the variable you made earlier. Here, this is a sub page of &amp;lt;tt&amp;gt;page_menu&amp;lt;/tt&amp;gt;, i.e. the MENU page, which was made earlier.&lt;br /&gt;
* name: similar to the name of a base page, it is used as the title entry of the sub page. If a sub page has a name (which it doesn't need to have), the name of the sub page overwrites the name of the base page, such allowing for slightly different titles on each &amp;quot;screen&amp;quot; of a CDU &amp;quot;page&amp;quot;. Note, however, that the display of the page count is taken care of, i.e. you do not have to put that into the title.&lt;br /&gt;
* ptp: same as with the base page. Also identical, the registration is changed to registration by ID when the DEBUG variable is non-zero.&lt;br /&gt;
&lt;br /&gt;
After a sub page has been made, one needs to make fields to actually hold content:&lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,&amp;quot;FMC&amp;quot;,page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
The first part creates a field, the field constructor is:&lt;br /&gt;
  new: func(label,data,key_action=nil,ptp=nil) {...};&lt;br /&gt;
This constructor is a little more complex than the previous ones:&lt;br /&gt;
* &amp;lt;tt&amp;gt;label&amp;lt;/tt&amp;gt;: the entry for the label line (the top line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;data&amp;lt;/tt&amp;gt;: the entry for data line (the lower line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;: as fields have an line select key associated with them, &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;, a function element, determines what happens when the LSK next to the data line is pressed.&lt;br /&gt;
* &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;: registering the field. As for base and sub pages, a non-zero DEBUG changes the ptp.&lt;br /&gt;
&lt;br /&gt;
In order to make the construction of a field a little more convenient, some very limited type of constructor overloading is incorporated. Both lines could be initialized with either an element of type &amp;lt;tt&amp;gt;ScreenText.new()&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;), i.e. a hash, or it can be initialized with a vector or elements, i.e. with &amp;lt;tt&amp;gt;[ScreenText.new() ScreenText.new() ...]&amp;lt;/tt&amp;gt;. (More on why this is nice to have later.)&lt;br /&gt;
&lt;br /&gt;
 # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
 page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
This part of the code puts this field into the top-left position in the sub page. Each sub page has two columns (&amp;lt;tt&amp;gt;SubPage.left_field[]&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;SubPage.right_field[]&amp;lt;/tt&amp;gt;) of six elements each. The columns are zero indexed.&lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_menu_default.activate();&lt;br /&gt;
This part activates this sup page. Sub page activation is slightly different from base page displaying. The later jumps to the base page and displays whatever sub page is active, &amp;lt;tt&amp;gt;SubPage.activate()&amp;lt;/tt&amp;gt; activates the corresponding sub page in the parent base page and then calls the display function of that page, effectively displaying the sub page.&lt;br /&gt;
&lt;br /&gt;
===Making a more complex SubPage===&lt;br /&gt;
Here just the code:&lt;br /&gt;
  #######################&lt;br /&gt;
  # DETAILS PAGE IDENT&lt;br /&gt;
  #######################&lt;br /&gt;
  #&lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make details for page &amp;quot;~&amp;quot;IDENT&amp;quot;):;&lt;br /&gt;
  &lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_ident_default = SubPage.new(page_ident,name=nil,ptp=&amp;quot;/sub_default&amp;quot;); &lt;br /&gt;
  &lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make fields for page &amp;quot;~&amp;quot;IDENT&amp;quot;):;&lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_model = Field.new(&amp;quot;MODEL&amp;quot;,ScreenText.new(['%s','/instrumentation/cdu/ident/model'],ScreenText[&amp;quot;WHITE&amp;quot;]));&lt;br /&gt;
  var field_engines = Field.new(&amp;quot;ENGINES&amp;quot;,ScreenText.new(['%s','/instrumentation/cdu/ident/engines'],ScreenText[&amp;quot;WHITE&amp;quot;]));&lt;br /&gt;
  var field_navData = Field.new(&amp;quot;NAV DATA&amp;quot;,&amp;quot;----&amp;quot;); &lt;br /&gt;
  var field_navData_active = Field.new(&amp;quot;ACTIVE&amp;quot;,&amp;quot;----&amp;quot;);&lt;br /&gt;
  var field_navData_inactive = Field.new(ScreenText.new(&amp;quot;INACTIVE&amp;quot;,ScreenText[&amp;quot;off&amp;quot;],nil),&amp;quot;----&amp;quot;); &lt;br /&gt;
  var field_dragFf = Field.new(&amp;quot;DRAG/FF&amp;quot;,&amp;quot;+0.0/+0.0&amp;quot;); &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_ident_default.left_field[0]=field_model;&lt;br /&gt;
  page_ident_default.left_field[1]=field_navData;&lt;br /&gt;
  page_ident_default.left_field[5]=page_index.home;&lt;br /&gt;
  page_ident_default.right_field[0]=field_engines;&lt;br /&gt;
  page_ident_default.right_field[1]=field_navData_active;&lt;br /&gt;
  page_ident_default.right_field[2]=field_navData_inactive;&lt;br /&gt;
  page_ident_default.right_field[4]=field_dragFf;&lt;br /&gt;
  page_ident_default.right_field[5]=page_pos_init.home;&lt;br /&gt;
  &lt;br /&gt;
  # place the separators&lt;br /&gt;
  page_ident_default.separators = [11];&lt;br /&gt;
  &lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_ident_default.activate();&lt;br /&gt;
The only new thing here is the use of the more complex version of the screen text constructor and the line&lt;br /&gt;
   page_ident_default.right_field[5]=page_pos_init.home;&lt;br /&gt;
What this does is assigning an auto-generate field of a sub page to a field in another sub page. Thes auto-generated fields can be used to directly activate these sub pages.&lt;br /&gt;
&lt;br /&gt;
= The CDU Screen = &lt;br /&gt;
One of the major problems of the CDU is the representation of the actual screen. According to the Honeywell manual, the CDU utilized by Boeing has a fixed setup.&lt;br /&gt;
&lt;br /&gt;
== Details of the (LCD) Screen ==&lt;br /&gt;
The LCD has '''14 lines''' with a total of '''24 characters per line'''. The page format is formatted as follows:&lt;br /&gt;
&lt;br /&gt;
* Title Field: The top line of the display area. Id identifies the subject or title of the data displayed on the page in view. It also identifies page number and the number of pages in series, e.g., &amp;lt;tt&amp;gt;1/2&amp;lt;/tt&amp;gt; identifies a page as the first in a series of two pages.&lt;br /&gt;
* Left Field: 6 pairs of lines, 11 characters per line. It extends from the left side of the screen to the center. The pilot has access to one line of each pair through a LSK (Line-Select Key) on the left side of the CDU. A line pair is made up of a label and a data line.&lt;br /&gt;
* Right Field: This field is similar to the left field, extending from the center of the screen to the right side. Pilot access is available by a LSK on the right side. &lt;br /&gt;
* Scratchpad: The bottom line of the display screen. This line displays alphanumeric data or messages. Data can be entered with the alphanumeric keys or the LSK, or by the FMC. Scratchpad entry cannot, normally, be made with a FMC message in the scratchpad. Scratchpad entries are independent of page selection, and remain until cleared even when page changes occur. Scratchpad data entries and erases affect only the associated CDU. Messages can appear and be erased on both CDUs simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Internal Representation ==&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The utilizes display matrix, showing the text bounding boxes for clarity.]]&lt;br /&gt;
As the screen has a &amp;quot;fixed&amp;quot; resolution, internally the screen is represented as a 14-by-24(-by-2) matrix. The zero-indexed matrix is held in the property tree:&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal double-type variable (although it is only integers).&lt;br /&gt;
&lt;br /&gt;
The style of the char is encoded via a binary key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt;  7&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name (used in the Nasal code for the CDU), which is resolved into a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
the first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;). The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet implemented. [[User:Hcc23|Hcc23]] 14:01, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Nasal Code ==&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;.&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields. Several elements can be concattenated in a single line by stacking them in a vector. The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text; or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background.&lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the text element. Here some limited constructor overloading can be used.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  var test_text = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  var test_prop = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
The last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;));&lt;br /&gt;
Furthermore, whenever a property is used in a screen text element on a subpage, the suppage, when displayed, registers listeners on all utilized properties, resulting in updated data on the screen. When the sup page is changed, the listeners are de-registered.&lt;br /&gt;
&lt;br /&gt;
== XML Code ==&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== Generating the offset code ===&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= The Property Tree =&lt;br /&gt;
&lt;br /&gt;
The [[CDU]] also has some properties in the general [[FlightGear]] [[Property Tree]].&lt;br /&gt;
In general it is located in &amp;lt;code&amp;gt;/instrumentation/cdu/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= A Brief History of the Boeing CDU in FlightGear =&lt;br /&gt;
Find some more information on the [[CDU]] at these pages:&lt;br /&gt;
* [[CDU]]&lt;br /&gt;
* [[Howto: Implement a Control Display Unit]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30898</id>
		<title>Howto:Coding a Boeing CDU</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30898"/>
		<updated>2011-04-08T21:01:58Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Nasal Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
[[User:Gijs|Gijs]] has started an effort to bring a generic Boeing [[CDU]] to [[FlightGear]]. This page tries to describe the coding for this effort.&lt;br /&gt;
&lt;br /&gt;
= The Sources =&lt;br /&gt;
The [[CDU]] currently resides in '''$FGDATA/Aircraft/Instruments-3d/cdu/'''.&lt;br /&gt;
&lt;br /&gt;
'''Graphics''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.ac&amp;lt;/tt&amp;gt;: This is a [[AC3D]] file, describing the 3D outline of the CDU model.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_brown.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_grey.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
&lt;br /&gt;
'''XML''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;: This is the main [[XML]] file, providing the direct interface between the 3D model and the code. This file also defines the keypress interactions and the positioning of the text to be displayed in the screen.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display-matrix-text.xml&amp;lt;/tt&amp;gt;: An OSGText &amp;quot;model&amp;quot;, used as a baseline for the texts on the screen. Compare to &amp;lt;tt&amp;gt;README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Nasal''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;: This is the main [[Nasal]] script file to be edited by the ''user'' of the CDU Nasal framework.&lt;br /&gt;
* &amp;lt;tt&amp;gt;cdu_page_framework.nas&amp;lt;/tt&amp;gt;: This is the main file of the CDU framework. It defines the main ''classes'' used for the CDU.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;: This file contains the Nasal relevant for the dispaly matrix. This code might be useful for other complex screen-based instruments.&lt;br /&gt;
* &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;: This file contains functions which I found useful for my project, but which are totally generic and could be used for other stuff as well.&lt;br /&gt;
* &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;: This file contains a rudimentary timer ''class'' and an example of how to incorporate this with a generic class for an instrument button, allowing the button to call different Nasal scripts, depending on how long it has been pressed. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;README&amp;lt;/tt&amp;gt;: Well, a readme.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Loading a CDU into an Aircraft ==&lt;br /&gt;
Here is how the CDU is loaded into the Boeing 777-200:&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;777-22ER-set.xml&amp;lt;/tt&amp;gt; the Nasal node is expanded as follows:&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- generic for the CDU --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/helping_functions.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/timer.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/cdu_page_framework.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;nowiki&amp;gt;&amp;lt;!-- specific for the B777 --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/b777_cdu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
Note the difference in the framework files and the actual ''instance'' used for this aircraft. To code pages for the CDU, one would normally not have to mess with the framework files. [[User:Hcc23|Hcc23]]&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Somewhere in the actual 3D model of the aircraft the &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; for the 3D model of the CDU has to be loaded. I haven't looked for that yet as that was already done for the 777-200. [[User:Hcc23|Hcc23]] 14:42, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== 3D Graphics ==&lt;br /&gt;
The 3D model resides in the file '''&amp;lt;tt&amp;gt;$FGDATA/Models/Cockpit/Instruments/CDU/cdu.ac&amp;lt;/tt&amp;gt;'''. This is a [[AC3D]] file format, but it should be importable by [[Blender]].&lt;br /&gt;
{|&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| [[File:CDU_3D_wireframe.png|thumb|270px|The wireframe of the 3D model and the corresponding coordinate system. ATTENTION: the axis are not right: RED is +X, GREEN is +Z, BLUE is -Y !]]&lt;br /&gt;
| [[File:CDU.png|thumb|270px|The texture of the CDU, a 512x512 PNG bitmap.]]&lt;br /&gt;
| [[File:CDU_3D_textures.png|thumb|270px|The resulting 3D model, after the textures have been added.]]&lt;br /&gt;
|}&lt;br /&gt;
The model also specifies the model internal coordinate system. It is indicated in the pictures through the corresponding axis: X (red), Y (green), and Z (blue). The origin of this coordinate system seems to coincide with the geometric center of the back plane of the [[CDU]], i.e. the YZ-plane is coplanar with the back of the [[CDU]]. The unit of the coordinate system is the SI unit ''Meter''.&lt;br /&gt;
&lt;br /&gt;
The 3D model has bindings defined to each button. So when a certain button is clicked, something happens. Right now most buttons are only used&lt;br /&gt;
to open other [[CDU]]-pages.&lt;br /&gt;
&lt;br /&gt;
=== The Screen of the CDU ===&lt;br /&gt;
With respect to the model coordinate frame, the screen is the rectangle given by:&lt;br /&gt;
&lt;br /&gt;
  Top edge:   z= 0.111, x=0.004&lt;br /&gt;
  Lower edge: z= 0.019, x=0.004&lt;br /&gt;
  Left edge:  y=-0.051, x=0.004&lt;br /&gt;
  Right edge: y= 0.051, x=0.004&lt;br /&gt;
&lt;br /&gt;
= The Code Framework =&lt;br /&gt;
&lt;br /&gt;
The CDU framework is implemented following some classic object-oriented ideas, completely implemented in Nasal. All variables are instanciated using &amp;lt;tt&amp;gt;var&amp;lt;/tt&amp;gt; so that the global namespace should not be tainted.&lt;br /&gt;
&lt;br /&gt;
The idea for the framework stems from the fact that a CDU is based upon the idea of ''pages'', some of which could occupy several screens. This, in conjunction with the idea of the ''fields'' (stipulated from the screen layout of the CDU) resulted in the following framework:&lt;br /&gt;
  CDU&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | | &lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | |&lt;br /&gt;
  | |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  |   |&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-...&lt;br /&gt;
Well, you get the idea....&lt;br /&gt;
&lt;br /&gt;
These three ''classes'' (BasePage, SubPage, Field) are defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;. The constructors are generally called &amp;lt;tt&amp;gt;.new()&amp;lt;/tt&amp;gt;, all ''memberss'' are created within the constructors, all ''static'' parts are implemented directly on the hash level.&lt;br /&gt;
&lt;br /&gt;
Beside these three classes the class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;) is used to house the actual text to be printed.&lt;br /&gt;
&lt;br /&gt;
All text is then kept internal to Nasal within the beforementioned structure. The text is then also kept in the FlightGear property tree so that an interface to osgtext can be established via &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' There is a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable set in the CDU framework. Setting this variable to non-zero enables a bunch of console printouts, implemented via &amp;lt;tt&amp;gt;DEBUG?print('....'):;&amp;lt;/tt&amp;gt; Furthermore, when calling a constructor, the parameter &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt; (for path-to-property) can be set, enabling some member variables of the classes to register themselves in the property tree, allowing an easier debugging during runtime. [[User:Hcc23|Hcc23]] 15:20, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
Maybe looking at the actual code is the easiest way of understanding how the framework works. (I also tried to be fairly explicit in my in-code comments, so looking at the sources should actually be helpful, too. [[User:Hcc23|Hcc23]] 15:46, 8 April 2011 (EDT))&lt;br /&gt;
&lt;br /&gt;
As the framework is separate from the ''instanciation'', let's focus on that as that is the part a ''user'' should care mostly about. The relevant file for the Boeing 777-200 is &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Preliminaries===&lt;br /&gt;
  #####################################################&lt;br /&gt;
  # These variables have already been defined in &lt;br /&gt;
  # cdu_page_framework but can (?) be redifined here &lt;br /&gt;
  # for slightly changed versions.&lt;br /&gt;
  #####################################################&lt;br /&gt;
  &lt;br /&gt;
  var ROWS = 14; 	# the number of lines the CDU has&lt;br /&gt;
  var COLS = 24; 	# the number of characters each line can hold&lt;br /&gt;
  var PROP = &amp;quot;/instrumentation/cdu&amp;quot;; 	# generic path to the properties of this CDU&lt;br /&gt;
  var DEBUG = 1; # enable a more verbose &amp;quot;debug&amp;quot; mode, i.e. register all kinds of stuff in the property tree&lt;br /&gt;
  &lt;br /&gt;
  resetDisplayMatrix();&lt;br /&gt;
This essential defines the size of the dispaly matrix, enables the debug printout and clears the display matrix in the property tree.&lt;br /&gt;
(&amp;lt;tt&amp;gt;resetDisplayMatrix();&amp;lt;/tt&amp;gt; fills the complete display matrix with spaces ( ) and also set the style to &amp;lt;tt&amp;gt;&amp;quot;off&amp;quot;&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
===Making the BasePages===&lt;br /&gt;
  # make the pages&lt;br /&gt;
  var page_menu      = BasePage.new(&amp;quot;MENU&amp;quot;,PROP~&amp;quot;/page_menu&amp;quot;); &lt;br /&gt;
  KeyBinding[&amp;quot;MENU&amp;quot;] = func() {page_menu.displayPage(); }; # Note : do NOT forget to wrap displayPage with a function!&lt;br /&gt;
  var page_index     = BasePage.new(&amp;quot;INDEX&amp;quot;,PROP~&amp;quot;/page_index&amp;quot;); &lt;br /&gt;
  var page_ident     = BasePage.new(&amp;quot;IDENT&amp;quot;,PROP~&amp;quot;/page_ident&amp;quot;); &lt;br /&gt;
  var page_pos       = BasePage.new(&amp;quot;POS&amp;quot;,PROP~&amp;quot;/page_pos&amp;quot;); &lt;br /&gt;
  var page_perf      = BasePage.new(&amp;quot;PERF&amp;quot;,PROP~&amp;quot;/page_perf&amp;quot;); &lt;br /&gt;
  var page_thrustLim = BasePage.new(&amp;quot;THRUST LIM&amp;quot;,PROP~&amp;quot;/page_thurstLim&amp;quot;); &lt;br /&gt;
  var page_takeoff   = BasePage.new(&amp;quot;TAKEOFF&amp;quot;,PROP~&amp;quot;/page_takeoff&amp;quot;); &lt;br /&gt;
  var page_approach  = BasePage.new(&amp;quot;APPROACH&amp;quot;,PROP~&amp;quot;/page_approach&amp;quot;); &lt;br /&gt;
  var page_navData   = BasePage.new(&amp;quot;NAV DATA&amp;quot;,PROP~&amp;quot;/page_navData&amp;quot;); &lt;br /&gt;
  var page_maint     = BasePage.new(&amp;quot;MAINT&amp;quot;,PROP~&amp;quot;/page_maint&amp;quot;); &lt;br /&gt;
This section creates the base pages of the CDU. The constructor for base pages is this one:&lt;br /&gt;
  new: func(name,ptp=nil) {...};&lt;br /&gt;
What this essentially does is creating a container to house sub pages. The &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element is used as the title of the page (but this could be overwritten in a sub page), the &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;, if set, registers the base page at that path. (However, if the &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable is set, the the pages are registered by their internal ID in a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; path underneath the CDU.)&lt;br /&gt;
&lt;br /&gt;
When a base page constructor is called, it also creates a ''home''-method. This function can be used to make the corresponding base page the active page, i.e. display that page. As you can see above, the corresponding method of the MENU page is assigned to the related button of the CDU. &amp;lt;tt&amp;gt;KeyBinding&amp;lt;/tt&amp;gt; is defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;, for a list of the available buttons see &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Making a SubPage (and the corresponding Fields)===&lt;br /&gt;
  #######################&lt;br /&gt;
  # DETAILS PAGE MENU&lt;br /&gt;
  #######################&lt;br /&gt;
  #&lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make details for page &amp;quot;~&amp;quot;MENU&amp;quot;):;&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_menu_default = SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,&amp;quot;FMC&amp;quot;,page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
  &lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_menu_default.activate();&lt;br /&gt;
This code section starts to fill in the details of the page MENU. As outlined in the framework, each base page houses sub pages, which in turn house the fields (which hold the actual content). So we need to start by making a sub page:&lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_menu_default = SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
The constructor for a sub page looks like this:&lt;br /&gt;
  new: func(parent_base_page,name=nil,ptp=nil) {...};&lt;br /&gt;
The elements are fairly straight forward:&lt;br /&gt;
* parent_base_page: parent node of this sub page (which is a base page). Note that this is not the name of that page, but the actual page, i.e. put down the name of the variable you made earlier. Here, this is a sub page of &amp;lt;tt&amp;gt;page_menu&amp;lt;/tt&amp;gt;, i.e. the MENU page, which was made earlier.&lt;br /&gt;
* name: similar to the name of a base page, it is used as the title entry of the sub page. If a sub page has a name (which it doesn't need to have), the name of the sub page overwrites the name of the base page, such allowing for slightly different titles on each &amp;quot;screen&amp;quot; of a CDU &amp;quot;page&amp;quot;. Note, however, that the display of the page count is taken care of, i.e. you do not have to put that into the title.&lt;br /&gt;
* ptp: same as with the base page. Also identical, the registration is changed to registration by ID when the DEBUG variable is non-zero.&lt;br /&gt;
&lt;br /&gt;
After a sub page has been made, one needs to make fields to actually hold content:&lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,&amp;quot;FMC&amp;quot;,page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
The first part creates a field, the field constructor is:&lt;br /&gt;
  new: func(label,data,key_action=nil,ptp=nil) {...};&lt;br /&gt;
This constructor is a little more complex than the previous ones:&lt;br /&gt;
* &amp;lt;tt&amp;gt;label&amp;lt;/tt&amp;gt;: the entry for the label line (the top line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;data&amp;lt;/tt&amp;gt;: the entry for data line (the lower line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;: as fields have an line select key associated with them, &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;, a function element, determines what happens when the LSK next to the data line is pressed.&lt;br /&gt;
* &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;: registering the field. As for base and sub pages, a non-zero DEBUG changes the ptp.&lt;br /&gt;
&lt;br /&gt;
In order to make the construction of a field a little more convenient, some very limited type of constructor overloading is incorporated. Both lines could be initialized with either an element of type &amp;lt;tt&amp;gt;ScreenText.new()&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;), i.e. a hash, or it can be initialized with a vector or elements, i.e. with &amp;lt;tt&amp;gt;[ScreenText.new() ScreenText.new() ...]&amp;lt;/tt&amp;gt;. (More on why this is nice to have later.)&lt;br /&gt;
&lt;br /&gt;
 # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
 page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
This part of the code puts this field into the top-left position in the sub page. Each sub page has two columns (&amp;lt;tt&amp;gt;SubPage.left_field[]&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;SubPage.right_field[]&amp;lt;/tt&amp;gt;) of six elements each. The columns are zero indexed.&lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_menu_default.activate();&lt;br /&gt;
This part activates this sup page. Sub page activation is slightly different from base page displaying. The later jumps to the base page and displays whatever sub page is active, &amp;lt;tt&amp;gt;SubPage.activate()&amp;lt;/tt&amp;gt; activates the corresponding sub page in the parent base page and then calls the display function of that page, effectively displaying the sub page.&lt;br /&gt;
&lt;br /&gt;
= The CDU Screen = &lt;br /&gt;
One of the major problems of the CDU is the representation of the actual screen. According to the Honeywell manual, the CDU utilized by Boeing has a fixed setup.&lt;br /&gt;
&lt;br /&gt;
== Details of the (LCD) Screen ==&lt;br /&gt;
The LCD has '''14 lines''' with a total of '''24 characters per line'''. The page format is formatted as follows:&lt;br /&gt;
&lt;br /&gt;
* Title Field: The top line of the display area. Id identifies the subject or title of the data displayed on the page in view. It also identifies page number and the number of pages in series, e.g., &amp;lt;tt&amp;gt;1/2&amp;lt;/tt&amp;gt; identifies a page as the first in a series of two pages.&lt;br /&gt;
* Left Field: 6 pairs of lines, 11 characters per line. It extends from the left side of the screen to the center. The pilot has access to one line of each pair through a LSK (Line-Select Key) on the left side of the CDU. A line pair is made up of a label and a data line.&lt;br /&gt;
* Right Field: This field is similar to the left field, extending from the center of the screen to the right side. Pilot access is available by a LSK on the right side. &lt;br /&gt;
* Scratchpad: The bottom line of the display screen. This line displays alphanumeric data or messages. Data can be entered with the alphanumeric keys or the LSK, or by the FMC. Scratchpad entry cannot, normally, be made with a FMC message in the scratchpad. Scratchpad entries are independent of page selection, and remain until cleared even when page changes occur. Scratchpad data entries and erases affect only the associated CDU. Messages can appear and be erased on both CDUs simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Internal Representation ==&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The utilizes display matrix, showing the text bounding boxes for clarity.]]&lt;br /&gt;
As the screen has a &amp;quot;fixed&amp;quot; resolution, internally the screen is represented as a 14-by-24(-by-2) matrix. The zero-indexed matrix is held in the property tree:&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal double-type variable (although it is only integers).&lt;br /&gt;
&lt;br /&gt;
The style of the char is encoded via a binary key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt;  7&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name (used in the Nasal code for the CDU), which is resolved into a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
the first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;). The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet implemented. [[User:Hcc23|Hcc23]] 14:01, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Nasal Code ==&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;.&lt;br /&gt;
The key element of making text appear on the 3D screen is the Nasal class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt;-elements make up the label and data lines of fields. Several elements can be concattenated in a single line by stacking them in a vector. The constructor for screen text is:&lt;br /&gt;
  new: func(t,s=32,ptp=nil)&lt;br /&gt;
The two elements are text (t) and style (s). Let's look at them in detail:&lt;br /&gt;
* &amp;lt;tt&amp;gt;s&amp;lt;/tt&amp;gt;: style is an integer according to the above binary key. In order to make life easier, one can directly use the ''static'' hash members, e.g. &amp;lt;tt&amp;gt;ScreenText[&amp;quot;white&amp;quot;]&amp;lt;/tt&amp;gt; for small, white text; or &amp;lt;tt&amp;gt;ScreenText[&amp;quot;GREEN_&amp;quot;]&amp;lt;/tt&amp;gt; for large, green text with a shaded background.&lt;br /&gt;
* &amp;lt;tt&amp;gt;t&amp;lt;/tt&amp;gt;: is the text element. Here some limited constructor overloading can be used.&lt;br /&gt;
&lt;br /&gt;
The constructor overlaoding allows for an easy creating of ''just'' plain text:&lt;br /&gt;
  var test_text = ScreenText.new(&amp;quot;Hello World!&amp;quot;,ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
However, it could also be used to get a property from the property tree.&lt;br /&gt;
  var test_prop = ScreenText.new([&amp;quot;This is a %s aircraft&amp;quot;,&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;],ScreenText[&amp;quot;WHITE&amp;quot;]);&lt;br /&gt;
The last call uses the property &amp;lt;tt&amp;gt;/instrumentation/cdu/ident/aircraft&amp;lt;tt&amp;gt; in a screen text element. The result is comparable to&lt;br /&gt;
  sprintf(&amp;quot;This is a %s aircraft&amp;quot;,getprop(&amp;quot;/instrumentation/cdu/ident/aircraft&amp;quot;));&lt;br /&gt;
Furthermore, whenever a property is used in a screen text element on a subpage, the suppage, when displayed, registers listeners on all utilized properties, resulting in updated data on the screen. When the sup page is changed, the listeners are de-registered.&lt;br /&gt;
&lt;br /&gt;
== XML Code ==&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== Generating the offset code ===&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= The Property Tree =&lt;br /&gt;
&lt;br /&gt;
The [[CDU]] also has some properties in the general [[FlightGear]] [[Property Tree]].&lt;br /&gt;
In general it is located in &amp;lt;code&amp;gt;/instrumentation/cdu/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= A Brief History of the Boeing CDU in FlightGear =&lt;br /&gt;
Find some more information on the [[CDU]] at these pages:&lt;br /&gt;
* [[CDU]]&lt;br /&gt;
* [[Howto: Implement a Control Display Unit]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30897</id>
		<title>Howto:Coding a Boeing CDU</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30897"/>
		<updated>2011-04-08T20:43:12Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Examples */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
[[User:Gijs|Gijs]] has started an effort to bring a generic Boeing [[CDU]] to [[FlightGear]]. This page tries to describe the coding for this effort.&lt;br /&gt;
&lt;br /&gt;
= The Sources =&lt;br /&gt;
The [[CDU]] currently resides in '''$FGDATA/Aircraft/Instruments-3d/cdu/'''.&lt;br /&gt;
&lt;br /&gt;
'''Graphics''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.ac&amp;lt;/tt&amp;gt;: This is a [[AC3D]] file, describing the 3D outline of the CDU model.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_brown.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_grey.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
&lt;br /&gt;
'''XML''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;: This is the main [[XML]] file, providing the direct interface between the 3D model and the code. This file also defines the keypress interactions and the positioning of the text to be displayed in the screen.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display-matrix-text.xml&amp;lt;/tt&amp;gt;: An OSGText &amp;quot;model&amp;quot;, used as a baseline for the texts on the screen. Compare to &amp;lt;tt&amp;gt;README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Nasal''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;: This is the main [[Nasal]] script file to be edited by the ''user'' of the CDU Nasal framework.&lt;br /&gt;
* &amp;lt;tt&amp;gt;cdu_page_framework.nas&amp;lt;/tt&amp;gt;: This is the main file of the CDU framework. It defines the main ''classes'' used for the CDU.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;: This file contains the Nasal relevant for the dispaly matrix. This code might be useful for other complex screen-based instruments.&lt;br /&gt;
* &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;: This file contains functions which I found useful for my project, but which are totally generic and could be used for other stuff as well.&lt;br /&gt;
* &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;: This file contains a rudimentary timer ''class'' and an example of how to incorporate this with a generic class for an instrument button, allowing the button to call different Nasal scripts, depending on how long it has been pressed. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;README&amp;lt;/tt&amp;gt;: Well, a readme.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Loading a CDU into an Aircraft ==&lt;br /&gt;
Here is how the CDU is loaded into the Boeing 777-200:&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;777-22ER-set.xml&amp;lt;/tt&amp;gt; the Nasal node is expanded as follows:&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- generic for the CDU --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/helping_functions.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/timer.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/cdu_page_framework.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;nowiki&amp;gt;&amp;lt;!-- specific for the B777 --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/b777_cdu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
Note the difference in the framework files and the actual ''instance'' used for this aircraft. To code pages for the CDU, one would normally not have to mess with the framework files. [[User:Hcc23|Hcc23]]&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Somewhere in the actual 3D model of the aircraft the &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; for the 3D model of the CDU has to be loaded. I haven't looked for that yet as that was already done for the 777-200. [[User:Hcc23|Hcc23]] 14:42, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== 3D Graphics ==&lt;br /&gt;
The 3D model resides in the file '''&amp;lt;tt&amp;gt;$FGDATA/Models/Cockpit/Instruments/CDU/cdu.ac&amp;lt;/tt&amp;gt;'''. This is a [[AC3D]] file format, but it should be importable by [[Blender]].&lt;br /&gt;
{|&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| [[File:CDU_3D_wireframe.png|thumb|270px|The wireframe of the 3D model and the corresponding coordinate system. ATTENTION: the axis are not right: RED is +X, GREEN is +Z, BLUE is -Y !]]&lt;br /&gt;
| [[File:CDU.png|thumb|270px|The texture of the CDU, a 512x512 PNG bitmap.]]&lt;br /&gt;
| [[File:CDU_3D_textures.png|thumb|270px|The resulting 3D model, after the textures have been added.]]&lt;br /&gt;
|}&lt;br /&gt;
The model also specifies the model internal coordinate system. It is indicated in the pictures through the corresponding axis: X (red), Y (green), and Z (blue). The origin of this coordinate system seems to coincide with the geometric center of the back plane of the [[CDU]], i.e. the YZ-plane is coplanar with the back of the [[CDU]]. The unit of the coordinate system is the SI unit ''Meter''.&lt;br /&gt;
&lt;br /&gt;
The 3D model has bindings defined to each button. So when a certain button is clicked, something happens. Right now most buttons are only used&lt;br /&gt;
to open other [[CDU]]-pages.&lt;br /&gt;
&lt;br /&gt;
=== The Screen of the CDU ===&lt;br /&gt;
With respect to the model coordinate frame, the screen is the rectangle given by:&lt;br /&gt;
&lt;br /&gt;
  Top edge:   z= 0.111, x=0.004&lt;br /&gt;
  Lower edge: z= 0.019, x=0.004&lt;br /&gt;
  Left edge:  y=-0.051, x=0.004&lt;br /&gt;
  Right edge: y= 0.051, x=0.004&lt;br /&gt;
&lt;br /&gt;
= The Code Framework =&lt;br /&gt;
&lt;br /&gt;
The CDU framework is implemented following some classic object-oriented ideas, completely implemented in Nasal. All variables are instanciated using &amp;lt;tt&amp;gt;var&amp;lt;/tt&amp;gt; so that the global namespace should not be tainted.&lt;br /&gt;
&lt;br /&gt;
The idea for the framework stems from the fact that a CDU is based upon the idea of ''pages'', some of which could occupy several screens. This, in conjunction with the idea of the ''fields'' (stipulated from the screen layout of the CDU) resulted in the following framework:&lt;br /&gt;
  CDU&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | | &lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | |&lt;br /&gt;
  | |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  |   |&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-...&lt;br /&gt;
Well, you get the idea....&lt;br /&gt;
&lt;br /&gt;
These three ''classes'' (BasePage, SubPage, Field) are defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;. The constructors are generally called &amp;lt;tt&amp;gt;.new()&amp;lt;/tt&amp;gt;, all ''memberss'' are created within the constructors, all ''static'' parts are implemented directly on the hash level.&lt;br /&gt;
&lt;br /&gt;
Beside these three classes the class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;) is used to house the actual text to be printed.&lt;br /&gt;
&lt;br /&gt;
All text is then kept internal to Nasal within the beforementioned structure. The text is then also kept in the FlightGear property tree so that an interface to osgtext can be established via &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' There is a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable set in the CDU framework. Setting this variable to non-zero enables a bunch of console printouts, implemented via &amp;lt;tt&amp;gt;DEBUG?print('....'):;&amp;lt;/tt&amp;gt; Furthermore, when calling a constructor, the parameter &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt; (for path-to-property) can be set, enabling some member variables of the classes to register themselves in the property tree, allowing an easier debugging during runtime. [[User:Hcc23|Hcc23]] 15:20, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
Maybe looking at the actual code is the easiest way of understanding how the framework works. (I also tried to be fairly explicit in my in-code comments, so looking at the sources should actually be helpful, too. [[User:Hcc23|Hcc23]] 15:46, 8 April 2011 (EDT))&lt;br /&gt;
&lt;br /&gt;
As the framework is separate from the ''instanciation'', let's focus on that as that is the part a ''user'' should care mostly about. The relevant file for the Boeing 777-200 is &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Preliminaries===&lt;br /&gt;
  #####################################################&lt;br /&gt;
  # These variables have already been defined in &lt;br /&gt;
  # cdu_page_framework but can (?) be redifined here &lt;br /&gt;
  # for slightly changed versions.&lt;br /&gt;
  #####################################################&lt;br /&gt;
  &lt;br /&gt;
  var ROWS = 14; 	# the number of lines the CDU has&lt;br /&gt;
  var COLS = 24; 	# the number of characters each line can hold&lt;br /&gt;
  var PROP = &amp;quot;/instrumentation/cdu&amp;quot;; 	# generic path to the properties of this CDU&lt;br /&gt;
  var DEBUG = 1; # enable a more verbose &amp;quot;debug&amp;quot; mode, i.e. register all kinds of stuff in the property tree&lt;br /&gt;
  &lt;br /&gt;
  resetDisplayMatrix();&lt;br /&gt;
This essential defines the size of the dispaly matrix, enables the debug printout and clears the display matrix in the property tree.&lt;br /&gt;
(&amp;lt;tt&amp;gt;resetDisplayMatrix();&amp;lt;/tt&amp;gt; fills the complete display matrix with spaces ( ) and also set the style to &amp;lt;tt&amp;gt;&amp;quot;off&amp;quot;&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
===Making the BasePages===&lt;br /&gt;
  # make the pages&lt;br /&gt;
  var page_menu      = BasePage.new(&amp;quot;MENU&amp;quot;,PROP~&amp;quot;/page_menu&amp;quot;); &lt;br /&gt;
  KeyBinding[&amp;quot;MENU&amp;quot;] = func() {page_menu.displayPage(); }; # Note : do NOT forget to wrap displayPage with a function!&lt;br /&gt;
  var page_index     = BasePage.new(&amp;quot;INDEX&amp;quot;,PROP~&amp;quot;/page_index&amp;quot;); &lt;br /&gt;
  var page_ident     = BasePage.new(&amp;quot;IDENT&amp;quot;,PROP~&amp;quot;/page_ident&amp;quot;); &lt;br /&gt;
  var page_pos       = BasePage.new(&amp;quot;POS&amp;quot;,PROP~&amp;quot;/page_pos&amp;quot;); &lt;br /&gt;
  var page_perf      = BasePage.new(&amp;quot;PERF&amp;quot;,PROP~&amp;quot;/page_perf&amp;quot;); &lt;br /&gt;
  var page_thrustLim = BasePage.new(&amp;quot;THRUST LIM&amp;quot;,PROP~&amp;quot;/page_thurstLim&amp;quot;); &lt;br /&gt;
  var page_takeoff   = BasePage.new(&amp;quot;TAKEOFF&amp;quot;,PROP~&amp;quot;/page_takeoff&amp;quot;); &lt;br /&gt;
  var page_approach  = BasePage.new(&amp;quot;APPROACH&amp;quot;,PROP~&amp;quot;/page_approach&amp;quot;); &lt;br /&gt;
  var page_navData   = BasePage.new(&amp;quot;NAV DATA&amp;quot;,PROP~&amp;quot;/page_navData&amp;quot;); &lt;br /&gt;
  var page_maint     = BasePage.new(&amp;quot;MAINT&amp;quot;,PROP~&amp;quot;/page_maint&amp;quot;); &lt;br /&gt;
This section creates the base pages of the CDU. The constructor for base pages is this one:&lt;br /&gt;
  new: func(name,ptp=nil) {...};&lt;br /&gt;
What this essentially does is creating a container to house sub pages. The &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element is used as the title of the page (but this could be overwritten in a sub page), the &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;, if set, registers the base page at that path. (However, if the &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable is set, the the pages are registered by their internal ID in a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; path underneath the CDU.)&lt;br /&gt;
&lt;br /&gt;
When a base page constructor is called, it also creates a ''home''-method. This function can be used to make the corresponding base page the active page, i.e. display that page. As you can see above, the corresponding method of the MENU page is assigned to the related button of the CDU. &amp;lt;tt&amp;gt;KeyBinding&amp;lt;/tt&amp;gt; is defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;, for a list of the available buttons see &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Making a SubPage (and the corresponding Fields)===&lt;br /&gt;
  #######################&lt;br /&gt;
  # DETAILS PAGE MENU&lt;br /&gt;
  #######################&lt;br /&gt;
  #&lt;br /&gt;
  DEBUG?print(&amp;quot;CDU_NOTE: Starting to make details for page &amp;quot;~&amp;quot;MENU&amp;quot;):;&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_menu_default = SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
  &lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,&amp;quot;FMC&amp;quot;,page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
  &lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_menu_default.activate();&lt;br /&gt;
This code section starts to fill in the details of the page MENU. As outlined in the framework, each base page houses sub pages, which in turn house the fields (which hold the actual content). So we need to start by making a sub page:&lt;br /&gt;
  # create the subpages&lt;br /&gt;
  var page_menu_default = SubPage.new(page_menu,&amp;quot;MENU&amp;quot;,page_menu.ptp~&amp;quot;/sub_default&amp;quot;);&lt;br /&gt;
The constructor for a sub page looks like this:&lt;br /&gt;
  new: func(parent_base_page,name=nil,ptp=nil) {...};&lt;br /&gt;
The elements are fairly straight forward:&lt;br /&gt;
* parent_base_page: parent node of this sub page (which is a base page). Note that this is not the name of that page, but the actual page, i.e. put down the name of the variable you made earlier. Here, this is a sub page of &amp;lt;tt&amp;gt;page_menu&amp;lt;/tt&amp;gt;, i.e. the MENU page, which was made earlier.&lt;br /&gt;
* name: similar to the name of a base page, it is used as the title entry of the sub page. If a sub page has a name (which it doesn't need to have), the name of the sub page overwrites the name of the base page, such allowing for slightly different titles on each &amp;quot;screen&amp;quot; of a CDU &amp;quot;page&amp;quot;. Note, however, that the display of the page count is taken care of, i.e. you do not have to put that into the title.&lt;br /&gt;
* ptp: same as with the base page. Also identical, the registration is changed to registration by ID when the DEBUG variable is non-zero.&lt;br /&gt;
&lt;br /&gt;
After a sub page has been made, one needs to make fields to actually hold content:&lt;br /&gt;
  # create the fields&lt;br /&gt;
  var field_fmc = Field.new(&amp;quot;&amp;quot;,&amp;quot;FMC&amp;quot;,page_ident.activate); &lt;br /&gt;
  &lt;br /&gt;
  # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
  page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
The first part creates a field, the field constructor is:&lt;br /&gt;
  new: func(label,data,key_action=nil,ptp=nil) {...};&lt;br /&gt;
This constructor is a little more complex than the previous ones:&lt;br /&gt;
* &amp;lt;tt&amp;gt;label&amp;lt;/tt&amp;gt;: the entry for the label line (the top line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;data&amp;lt;/tt&amp;gt;: the entry for data line (the lower line) of the field.&lt;br /&gt;
* &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;: as fields have an line select key associated with them, &amp;lt;tt&amp;gt;key_action&amp;lt;/tt&amp;gt;, a function element, determines what happens when the LSK next to the data line is pressed.&lt;br /&gt;
* &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;: registering the field. As for base and sub pages, a non-zero DEBUG changes the ptp.&lt;br /&gt;
&lt;br /&gt;
In order to make the construction of a field a little more convenient, some very limited type of constructor overloading is incorporated. Both lines could be initialized with either an element of type &amp;lt;tt&amp;gt;ScreenText.new()&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;), i.e. a hash, or it can be initialized with a vector or elements, i.e. with &amp;lt;tt&amp;gt;[ScreenText.new() ScreenText.new() ...]&amp;lt;/tt&amp;gt;. (More on why this is nice to have later.)&lt;br /&gt;
&lt;br /&gt;
 # register the fields in the subpage, remember, it's zero indexed&lt;br /&gt;
 page_menu_default.left_field[0]=field_fmc;&lt;br /&gt;
This part of the code puts this field into the top-left position in the sub page. Each sub page has two columns (&amp;lt;tt&amp;gt;SubPage.left_field[]&amp;lt;/tt&amp;gt; and &amp;lt;tt&amp;gt;SubPage.right_field[]&amp;lt;/tt&amp;gt;) of six elements each. The columns are zero indexed.&lt;br /&gt;
  #activate the page (and display it consequentially)&lt;br /&gt;
  page_menu_default.activate();&lt;br /&gt;
This part activates this sup page. Sub page activation is slightly different from base page displaying. The later jumps to the base page and displays whatever sub page is active, &amp;lt;tt&amp;gt;SubPage.activate()&amp;lt;/tt&amp;gt; activates the corresponding sub page in the parent base page and then calls the display function of that page, effectively displaying the sub page.&lt;br /&gt;
&lt;br /&gt;
= The CDU Screen = &lt;br /&gt;
One of the major problems of the CDU is the representation of the actual screen. According to the Honeywell manual, the CDU utilized by Boeing has a fixed setup.&lt;br /&gt;
&lt;br /&gt;
== Details of the (LCD) Screen ==&lt;br /&gt;
The LCD has '''14 lines''' with a total of '''24 characters per line'''. The page format is formatted as follows:&lt;br /&gt;
&lt;br /&gt;
* Title Field: The top line of the display area. Id identifies the subject or title of the data displayed on the page in view. It also identifies page number and the number of pages in series, e.g., &amp;lt;tt&amp;gt;1/2&amp;lt;/tt&amp;gt; identifies a page as the first in a series of two pages.&lt;br /&gt;
* Left Field: 6 pairs of lines, 11 characters per line. It extends from the left side of the screen to the center. The pilot has access to one line of each pair through a LSK (Line-Select Key) on the left side of the CDU. A line pair is made up of a label and a data line.&lt;br /&gt;
* Right Field: This field is similar to the left field, extending from the center of the screen to the right side. Pilot access is available by a LSK on the right side. &lt;br /&gt;
* Scratchpad: The bottom line of the display screen. This line displays alphanumeric data or messages. Data can be entered with the alphanumeric keys or the LSK, or by the FMC. Scratchpad entry cannot, normally, be made with a FMC message in the scratchpad. Scratchpad entries are independent of page selection, and remain until cleared even when page changes occur. Scratchpad data entries and erases affect only the associated CDU. Messages can appear and be erased on both CDUs simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Internal Representation ==&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The utilizes display matrix, showing the text bounding boxes for clarity.]]&lt;br /&gt;
As the screen has a &amp;quot;fixed&amp;quot; resolution, internally the screen is represented as a 14-by-24(-by-2) matrix. The zero-indexed matrix is held in the property tree:&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal double-type variable (although it is only integers).&lt;br /&gt;
&lt;br /&gt;
The style of the char is encoded via a binary key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt;  7&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name (used in the Nasal code for the CDU), which is resolved into a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
the first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;). The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet implemented. [[User:Hcc23|Hcc23]] 14:01, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Nasal Code ==&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
== XML Code ==&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== Generating the offset code ===&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= The Property Tree =&lt;br /&gt;
&lt;br /&gt;
The [[CDU]] also has some properties in the general [[FlightGear]] [[Property Tree]].&lt;br /&gt;
In general it is located in &amp;lt;code&amp;gt;/instrumentation/cdu/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= A Brief History of the Boeing CDU in FlightGear =&lt;br /&gt;
Find some more information on the [[CDU]] at these pages:&lt;br /&gt;
* [[CDU]]&lt;br /&gt;
* [[Howto: Implement a Control Display Unit]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30896</id>
		<title>Howto:Coding a Boeing CDU</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30896"/>
		<updated>2011-04-08T19:46:56Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* The Code Framework */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
[[User:Gijs|Gijs]] has started an effort to bring a generic Boeing [[CDU]] to [[FlightGear]]. This page tries to describe the coding for this effort.&lt;br /&gt;
&lt;br /&gt;
= The Sources =&lt;br /&gt;
The [[CDU]] currently resides in '''$FGDATA/Aircraft/Instruments-3d/cdu/'''.&lt;br /&gt;
&lt;br /&gt;
'''Graphics''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.ac&amp;lt;/tt&amp;gt;: This is a [[AC3D]] file, describing the 3D outline of the CDU model.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_brown.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_grey.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
&lt;br /&gt;
'''XML''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;: This is the main [[XML]] file, providing the direct interface between the 3D model and the code. This file also defines the keypress interactions and the positioning of the text to be displayed in the screen.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display-matrix-text.xml&amp;lt;/tt&amp;gt;: An OSGText &amp;quot;model&amp;quot;, used as a baseline for the texts on the screen. Compare to &amp;lt;tt&amp;gt;README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Nasal''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;: This is the main [[Nasal]] script file to be edited by the ''user'' of the CDU Nasal framework.&lt;br /&gt;
* &amp;lt;tt&amp;gt;cdu_page_framework.nas&amp;lt;/tt&amp;gt;: This is the main file of the CDU framework. It defines the main ''classes'' used for the CDU.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;: This file contains the Nasal relevant for the dispaly matrix. This code might be useful for other complex screen-based instruments.&lt;br /&gt;
* &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;: This file contains functions which I found useful for my project, but which are totally generic and could be used for other stuff as well.&lt;br /&gt;
* &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;: This file contains a rudimentary timer ''class'' and an example of how to incorporate this with a generic class for an instrument button, allowing the button to call different Nasal scripts, depending on how long it has been pressed. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;README&amp;lt;/tt&amp;gt;: Well, a readme.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Loading a CDU into an Aircraft ==&lt;br /&gt;
Here is how the CDU is loaded into the Boeing 777-200:&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;777-22ER-set.xml&amp;lt;/tt&amp;gt; the Nasal node is expanded as follows:&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- generic for the CDU --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/helping_functions.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/timer.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/cdu_page_framework.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;nowiki&amp;gt;&amp;lt;!-- specific for the B777 --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/b777_cdu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
Note the difference in the framework files and the actual ''instance'' used for this aircraft. To code pages for the CDU, one would normally not have to mess with the framework files. [[User:Hcc23|Hcc23]]&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Somewhere in the actual 3D model of the aircraft the &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; for the 3D model of the CDU has to be loaded. I haven't looked for that yet as that was already done for the 777-200. [[User:Hcc23|Hcc23]] 14:42, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== 3D Graphics ==&lt;br /&gt;
The 3D model resides in the file '''&amp;lt;tt&amp;gt;$FGDATA/Models/Cockpit/Instruments/CDU/cdu.ac&amp;lt;/tt&amp;gt;'''. This is a [[AC3D]] file format, but it should be importable by [[Blender]].&lt;br /&gt;
{|&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| [[File:CDU_3D_wireframe.png|thumb|270px|The wireframe of the 3D model and the corresponding coordinate system. ATTENTION: the axis are not right: RED is +X, GREEN is +Z, BLUE is -Y !]]&lt;br /&gt;
| [[File:CDU.png|thumb|270px|The texture of the CDU, a 512x512 PNG bitmap.]]&lt;br /&gt;
| [[File:CDU_3D_textures.png|thumb|270px|The resulting 3D model, after the textures have been added.]]&lt;br /&gt;
|}&lt;br /&gt;
The model also specifies the model internal coordinate system. It is indicated in the pictures through the corresponding axis: X (red), Y (green), and Z (blue). The origin of this coordinate system seems to coincide with the geometric center of the back plane of the [[CDU]], i.e. the YZ-plane is coplanar with the back of the [[CDU]]. The unit of the coordinate system is the SI unit ''Meter''.&lt;br /&gt;
&lt;br /&gt;
The 3D model has bindings defined to each button. So when a certain button is clicked, something happens. Right now most buttons are only used&lt;br /&gt;
to open other [[CDU]]-pages.&lt;br /&gt;
&lt;br /&gt;
=== The Screen of the CDU ===&lt;br /&gt;
With respect to the model coordinate frame, the screen is the rectangle given by:&lt;br /&gt;
&lt;br /&gt;
  Top edge:   z= 0.111, x=0.004&lt;br /&gt;
  Lower edge: z= 0.019, x=0.004&lt;br /&gt;
  Left edge:  y=-0.051, x=0.004&lt;br /&gt;
  Right edge: y= 0.051, x=0.004&lt;br /&gt;
&lt;br /&gt;
= The Code Framework =&lt;br /&gt;
&lt;br /&gt;
The CDU framework is implemented following some classic object-oriented ideas, completely implemented in Nasal. All variables are instanciated using &amp;lt;tt&amp;gt;var&amp;lt;/tt&amp;gt; so that the global namespace should not be tainted.&lt;br /&gt;
&lt;br /&gt;
The idea for the framework stems from the fact that a CDU is based upon the idea of ''pages'', some of which could occupy several screens. This, in conjunction with the idea of the ''fields'' (stipulated from the screen layout of the CDU) resulted in the following framework:&lt;br /&gt;
  CDU&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | | &lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | |&lt;br /&gt;
  | |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  |   |&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-...&lt;br /&gt;
Well, you get the idea....&lt;br /&gt;
&lt;br /&gt;
These three ''classes'' (BasePage, SubPage, Field) are defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;. The constructors are generally called &amp;lt;tt&amp;gt;.new()&amp;lt;/tt&amp;gt;, all ''memberss'' are created within the constructors, all ''static'' parts are implemented directly on the hash level.&lt;br /&gt;
&lt;br /&gt;
Beside these three classes the class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;) is used to house the actual text to be printed.&lt;br /&gt;
&lt;br /&gt;
All text is then kept internal to Nasal within the beforementioned structure. The text is then also kept in the FlightGear property tree so that an interface to osgtext can be established via &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' There is a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable set in the CDU framework. Setting this variable to non-zero enables a bunch of console printouts, implemented via &amp;lt;tt&amp;gt;DEBUG?print('....'):;&amp;lt;/tt&amp;gt; Furthermore, when calling a constructor, the parameter &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt; (for path-to-property) can be set, enabling some member variables of the classes to register themselves in the property tree, allowing an easier debugging during runtime. [[User:Hcc23|Hcc23]] 15:20, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Examples ==&lt;br /&gt;
Maybe looking at the actual code is the easiest way of understanding how the framework works. (I also tried to be fairly explicit in my in-code comments, so looking at the sources should actually be helpful, too. [[User:Hcc23|Hcc23]] 15:46, 8 April 2011 (EDT))&lt;br /&gt;
&lt;br /&gt;
As the framework is separate from the ''instanciation'', let's focus on that as that is the part a ''user'' should care mostly about. The relevant file for the Boeing 777-200 is &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''Some preliminaries:'''&lt;br /&gt;
  #####################################################&lt;br /&gt;
  # These variables have already been defined in &lt;br /&gt;
  # cdu_page_framework but can (?) be redifined here &lt;br /&gt;
  # for slightly changed versions.&lt;br /&gt;
  #####################################################&lt;br /&gt;
  &lt;br /&gt;
  var ROWS = 14; 	# the number of lines the CDU has&lt;br /&gt;
  var COLS = 24; 	# the number of characters each line can hold&lt;br /&gt;
  var PROP = &amp;quot;/instrumentation/cdu&amp;quot;; 	# generic path to the properties of this CDU&lt;br /&gt;
  var DEBUG = 1; # enable a more verbose &amp;quot;debug&amp;quot; mode, i.e. register all kinds of stuff in the property tree&lt;br /&gt;
  &lt;br /&gt;
  resetDisplayMatrix();&lt;br /&gt;
This essential defines the size of the dispaly matrix, enables the debug printout and clears the display matrix in the property tree.&lt;br /&gt;
(&amp;lt;tt&amp;gt;resetDisplayMatrix();&amp;lt;/tt&amp;gt; fills the complete display matrix with spaces ( ) and also set the style to &amp;lt;tt&amp;gt;&amp;quot;off&amp;quot;&amp;lt;/tt&amp;gt;.)&lt;br /&gt;
&lt;br /&gt;
'''Making the BasePages''':&lt;br /&gt;
  # make the pages&lt;br /&gt;
  var page_menu      = BasePage.new(&amp;quot;MENU&amp;quot;,PROP~&amp;quot;/page_menu&amp;quot;); &lt;br /&gt;
  KeyBinding[&amp;quot;MENU&amp;quot;] = func() {page_menu.displayPage(); }; # Note : do NOT forget to wrap displayPage with a function!&lt;br /&gt;
  var page_index     = BasePage.new(&amp;quot;INDEX&amp;quot;,PROP~&amp;quot;/page_index&amp;quot;); &lt;br /&gt;
  var page_ident     = BasePage.new(&amp;quot;IDENT&amp;quot;,PROP~&amp;quot;/page_ident&amp;quot;); &lt;br /&gt;
  var page_pos       = BasePage.new(&amp;quot;POS&amp;quot;,PROP~&amp;quot;/page_pos&amp;quot;); &lt;br /&gt;
  var page_perf      = BasePage.new(&amp;quot;PERF&amp;quot;,PROP~&amp;quot;/page_perf&amp;quot;); &lt;br /&gt;
  var page_thrustLim = BasePage.new(&amp;quot;THRUST LIM&amp;quot;,PROP~&amp;quot;/page_thurstLim&amp;quot;); &lt;br /&gt;
  var page_takeoff   = BasePage.new(&amp;quot;TAKEOFF&amp;quot;,PROP~&amp;quot;/page_takeoff&amp;quot;); &lt;br /&gt;
  var page_approach  = BasePage.new(&amp;quot;APPROACH&amp;quot;,PROP~&amp;quot;/page_approach&amp;quot;); &lt;br /&gt;
  var page_navData   = BasePage.new(&amp;quot;NAV DATA&amp;quot;,PROP~&amp;quot;/page_navData&amp;quot;); &lt;br /&gt;
  var page_maint     = BasePage.new(&amp;quot;MAINT&amp;quot;,PROP~&amp;quot;/page_maint&amp;quot;); &lt;br /&gt;
This section creates the base pages of the CDU. The constructor for base pages is this one:&lt;br /&gt;
  new: func(name,ptp=nil) {...}&lt;br /&gt;
What this essentially does is creating a container to house sub pages. The &amp;lt;tt&amp;gt;name&amp;lt;/tt&amp;gt; element is used as the title of the page (but this could be overwritten in a sub page), the &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt;, if set, registers the base page at that path. (However, if the &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable is set, the the pages are registered by their internal ID in a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; path underneath the CDU.)&lt;br /&gt;
&lt;br /&gt;
When a base page constructor is called, it also creates a ''home''-method. This function can be used to make the corresponding base page the active page, i.e. display that page. As you can see above, the corresponding method of the MENU page is assigned to the related button of the CDU. &amp;lt;tt&amp;gt;KeyBinding&amp;lt;/tt&amp;gt; is defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;, for a list of the available buttons see &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Making a SubPage''':&lt;br /&gt;
&lt;br /&gt;
= The CDU Screen = &lt;br /&gt;
One of the major problems of the CDU is the representation of the actual screen. According to the Honeywell manual, the CDU utilized by Boeing has a fixed setup.&lt;br /&gt;
&lt;br /&gt;
== Details of the (LCD) Screen ==&lt;br /&gt;
The LCD has '''14 lines''' with a total of '''24 characters per line'''. The page format is formatted as follows:&lt;br /&gt;
&lt;br /&gt;
* Title Field: The top line of the display area. Id identifies the subject or title of the data displayed on the page in view. It also identifies page number and the number of pages in series, e.g., &amp;lt;tt&amp;gt;1/2&amp;lt;/tt&amp;gt; identifies a page as the first in a series of two pages.&lt;br /&gt;
* Left Field: 6 pairs of lines, 11 characters per line. It extends from the left side of the screen to the center. The pilot has access to one line of each pair through a LSK (Line-Select Key) on the left side of the CDU. A line pair is made up of a label and a data line.&lt;br /&gt;
* Right Field: This field is similar to the left field, extending from the center of the screen to the right side. Pilot access is available by a LSK on the right side. &lt;br /&gt;
* Scratchpad: The bottom line of the display screen. This line displays alphanumeric data or messages. Data can be entered with the alphanumeric keys or the LSK, or by the FMC. Scratchpad entry cannot, normally, be made with a FMC message in the scratchpad. Scratchpad entries are independent of page selection, and remain until cleared even when page changes occur. Scratchpad data entries and erases affect only the associated CDU. Messages can appear and be erased on both CDUs simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Internal Representation ==&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The utilizes display matrix, showing the text bounding boxes for clarity.]]&lt;br /&gt;
As the screen has a &amp;quot;fixed&amp;quot; resolution, internally the screen is represented as a 14-by-24(-by-2) matrix. The zero-indexed matrix is held in the property tree:&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal double-type variable (although it is only integers).&lt;br /&gt;
&lt;br /&gt;
The style of the char is encoded via a binary key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt;  7&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name (used in the Nasal code for the CDU), which is resolved into a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
the first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;). The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet implemented. [[User:Hcc23|Hcc23]] 14:01, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Nasal Code ==&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
== XML Code ==&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== Generating the offset code ===&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= The Property Tree =&lt;br /&gt;
&lt;br /&gt;
The [[CDU]] also has some properties in the general [[FlightGear]] [[Property Tree]].&lt;br /&gt;
In general it is located in &amp;lt;code&amp;gt;/instrumentation/cdu/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= A Brief History of the Boeing CDU in FlightGear =&lt;br /&gt;
Find some more information on the [[CDU]] at these pages:&lt;br /&gt;
* [[CDU]]&lt;br /&gt;
* [[Howto: Implement a Control Display Unit]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30895</id>
		<title>Howto:Coding a Boeing CDU</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30895"/>
		<updated>2011-04-08T19:20:12Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* The Code Framework */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
[[User:Gijs|Gijs]] has started an effort to bring a generic Boeing [[CDU]] to [[FlightGear]]. This page tries to describe the coding for this effort.&lt;br /&gt;
&lt;br /&gt;
= The Sources =&lt;br /&gt;
The [[CDU]] currently resides in '''$FGDATA/Aircraft/Instruments-3d/cdu/'''.&lt;br /&gt;
&lt;br /&gt;
'''Graphics''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.ac&amp;lt;/tt&amp;gt;: This is a [[AC3D]] file, describing the 3D outline of the CDU model.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_brown.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_grey.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
&lt;br /&gt;
'''XML''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;: This is the main [[XML]] file, providing the direct interface between the 3D model and the code. This file also defines the keypress interactions and the positioning of the text to be displayed in the screen.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display-matrix-text.xml&amp;lt;/tt&amp;gt;: An OSGText &amp;quot;model&amp;quot;, used as a baseline for the texts on the screen. Compare to &amp;lt;tt&amp;gt;README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Nasal''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;: This is the main [[Nasal]] script file to be edited by the ''user'' of the CDU Nasal framework.&lt;br /&gt;
* &amp;lt;tt&amp;gt;cdu_page_framework.nas&amp;lt;/tt&amp;gt;: This is the main file of the CDU framework. It defines the main ''classes'' used for the CDU.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;: This file contains the Nasal relevant for the dispaly matrix. This code might be useful for other complex screen-based instruments.&lt;br /&gt;
* &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;: This file contains functions which I found useful for my project, but which are totally generic and could be used for other stuff as well.&lt;br /&gt;
* &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;: This file contains a rudimentary timer ''class'' and an example of how to incorporate this with a generic class for an instrument button, allowing the button to call different Nasal scripts, depending on how long it has been pressed. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;README&amp;lt;/tt&amp;gt;: Well, a readme.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Loading a CDU into an Aircraft ==&lt;br /&gt;
Here is how the CDU is loaded into the Boeing 777-200:&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;777-22ER-set.xml&amp;lt;/tt&amp;gt; the Nasal node is expanded as follows:&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- generic for the CDU --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/helping_functions.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/timer.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/cdu_page_framework.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;nowiki&amp;gt;&amp;lt;!-- specific for the B777 --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/b777_cdu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
Note the difference in the framework files and the actual ''instance'' used for this aircraft. To code pages for the CDU, one would normally not have to mess with the framework files. [[User:Hcc23|Hcc23]]&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Somewhere in the actual 3D model of the aircraft the &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; for the 3D model of the CDU has to be loaded. I haven't looked for that yet as that was already done for the 777-200. [[User:Hcc23|Hcc23]] 14:42, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== 3D Graphics ==&lt;br /&gt;
The 3D model resides in the file '''&amp;lt;tt&amp;gt;$FGDATA/Models/Cockpit/Instruments/CDU/cdu.ac&amp;lt;/tt&amp;gt;'''. This is a [[AC3D]] file format, but it should be importable by [[Blender]].&lt;br /&gt;
{|&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| [[File:CDU_3D_wireframe.png|thumb|270px|The wireframe of the 3D model and the corresponding coordinate system. ATTENTION: the axis are not right: RED is +X, GREEN is +Z, BLUE is -Y !]]&lt;br /&gt;
| [[File:CDU.png|thumb|270px|The texture of the CDU, a 512x512 PNG bitmap.]]&lt;br /&gt;
| [[File:CDU_3D_textures.png|thumb|270px|The resulting 3D model, after the textures have been added.]]&lt;br /&gt;
|}&lt;br /&gt;
The model also specifies the model internal coordinate system. It is indicated in the pictures through the corresponding axis: X (red), Y (green), and Z (blue). The origin of this coordinate system seems to coincide with the geometric center of the back plane of the [[CDU]], i.e. the YZ-plane is coplanar with the back of the [[CDU]]. The unit of the coordinate system is the SI unit ''Meter''.&lt;br /&gt;
&lt;br /&gt;
The 3D model has bindings defined to each button. So when a certain button is clicked, something happens. Right now most buttons are only used&lt;br /&gt;
to open other [[CDU]]-pages.&lt;br /&gt;
&lt;br /&gt;
=== The Screen of the CDU ===&lt;br /&gt;
With respect to the model coordinate frame, the screen is the rectangle given by:&lt;br /&gt;
&lt;br /&gt;
  Top edge:   z= 0.111, x=0.004&lt;br /&gt;
  Lower edge: z= 0.019, x=0.004&lt;br /&gt;
  Left edge:  y=-0.051, x=0.004&lt;br /&gt;
  Right edge: y= 0.051, x=0.004&lt;br /&gt;
&lt;br /&gt;
= The Code Framework =&lt;br /&gt;
&lt;br /&gt;
The CDU framework is implemented following some classic object-oriented ideas, completely implemented in Nasal. All variables are instanciated using &amp;lt;tt&amp;gt;var&amp;lt;/tt&amp;gt; so that the global namespace should not be tainted.&lt;br /&gt;
&lt;br /&gt;
The idea for the framework stems from the fact that a CDU is based upon the idea of ''pages'', some of which could occupy several screens. This, in conjunction with the idea of the ''fields'' (stipulated from the screen layout of the CDU) resulted in the following framework:&lt;br /&gt;
  CDU&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | | &lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-Field&lt;br /&gt;
  | | |-...&lt;br /&gt;
  | |&lt;br /&gt;
  | |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-BasePage&lt;br /&gt;
  | |&lt;br /&gt;
  | |-SubPage&lt;br /&gt;
  |   |&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-Field&lt;br /&gt;
  |   |-...&lt;br /&gt;
  |&lt;br /&gt;
  |-...&lt;br /&gt;
Well, you get the idea....&lt;br /&gt;
&lt;br /&gt;
These three ''classes'' (BasePage, SubPage, Field) are defined in &amp;lt;tt&amp;gt;cdu_framework.nas&amp;lt;/tt&amp;gt;. The constructors are generally called &amp;lt;tt&amp;gt;.new()&amp;lt;/tt&amp;gt;, all ''memberss'' are created within the constructors, all ''static'' parts are implemented directly on the hash level.&lt;br /&gt;
&lt;br /&gt;
Beside these three classes the class &amp;lt;tt&amp;gt;ScreenText&amp;lt;/tt&amp;gt; (defined in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;) is used to house the actual text to be printed.&lt;br /&gt;
&lt;br /&gt;
All text is then kept internal to Nasal within the beforementioned structure. The text is then also kept in the FlightGear property tree so that an interface to osgtext can be established via &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' There is a &amp;lt;tt&amp;gt;DEBUG&amp;lt;/tt&amp;gt; variable set in the CDU framework. Setting this variable to non-zero enables a bunch of console printouts, implemented via &amp;lt;tt&amp;gt;DEBUG?print('....'):;&amp;lt;/tt&amp;gt; Furthermore, when calling a constructor, the parameter &amp;lt;tt&amp;gt;ptp&amp;lt;/tt&amp;gt; (for path-to-property) can be set, enabling some member variables of the classes to register themselves in the property tree, allowing an easier debugging during runtime. [[User:Hcc23|Hcc23]] 15:20, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
= The CDU Screen = &lt;br /&gt;
One of the major problems of the CDU is the representation of the actual screen. According to the Honeywell manual, the CDU utilized by Boeing has a fixed setup.&lt;br /&gt;
&lt;br /&gt;
== Details of the (LCD) Screen ==&lt;br /&gt;
The LCD has '''14 lines''' with a total of '''24 characters per line'''. The page format is formatted as follows:&lt;br /&gt;
&lt;br /&gt;
* Title Field: The top line of the display area. Id identifies the subject or title of the data displayed on the page in view. It also identifies page number and the number of pages in series, e.g., &amp;lt;tt&amp;gt;1/2&amp;lt;/tt&amp;gt; identifies a page as the first in a series of two pages.&lt;br /&gt;
* Left Field: 6 pairs of lines, 11 characters per line. It extends from the left side of the screen to the center. The pilot has access to one line of each pair through a LSK (Line-Select Key) on the left side of the CDU. A line pair is made up of a label and a data line.&lt;br /&gt;
* Right Field: This field is similar to the left field, extending from the center of the screen to the right side. Pilot access is available by a LSK on the right side. &lt;br /&gt;
* Scratchpad: The bottom line of the display screen. This line displays alphanumeric data or messages. Data can be entered with the alphanumeric keys or the LSK, or by the FMC. Scratchpad entry cannot, normally, be made with a FMC message in the scratchpad. Scratchpad entries are independent of page selection, and remain until cleared even when page changes occur. Scratchpad data entries and erases affect only the associated CDU. Messages can appear and be erased on both CDUs simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Internal Representation ==&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The utilizes display matrix, showing the text bounding boxes for clarity.]]&lt;br /&gt;
As the screen has a &amp;quot;fixed&amp;quot; resolution, internally the screen is represented as a 14-by-24(-by-2) matrix. The zero-indexed matrix is held in the property tree:&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal double-type variable (although it is only integers).&lt;br /&gt;
&lt;br /&gt;
The style of the char is encoded via a binary key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt;  7&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name (used in the Nasal code for the CDU), which is resolved into a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
the first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;). The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet implemented. [[User:Hcc23|Hcc23]] 14:01, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Nasal Code ==&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
== XML Code ==&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== Generating the offset code ===&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= The Property Tree =&lt;br /&gt;
&lt;br /&gt;
The [[CDU]] also has some properties in the general [[FlightGear]] [[Property Tree]].&lt;br /&gt;
In general it is located in &amp;lt;code&amp;gt;/instrumentation/cdu/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= A Brief History of the Boeing CDU in FlightGear =&lt;br /&gt;
Find some more information on the [[CDU]] at these pages:&lt;br /&gt;
* [[CDU]]&lt;br /&gt;
* [[Howto: Implement a Control Display Unit]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30894</id>
		<title>Howto:Coding a Boeing CDU</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30894"/>
		<updated>2011-04-08T18:43:37Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
[[User:Gijs|Gijs]] has started an effort to bring a generic Boeing [[CDU]] to [[FlightGear]]. This page tries to describe the coding for this effort.&lt;br /&gt;
&lt;br /&gt;
= The Sources =&lt;br /&gt;
The [[CDU]] currently resides in '''$FGDATA/Aircraft/Instruments-3d/cdu/'''.&lt;br /&gt;
&lt;br /&gt;
'''Graphics''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.ac&amp;lt;/tt&amp;gt;: This is a [[AC3D]] file, describing the 3D outline of the CDU model.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_brown.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_grey.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
&lt;br /&gt;
'''XML''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;: This is the main [[XML]] file, providing the direct interface between the 3D model and the code. This file also defines the keypress interactions and the positioning of the text to be displayed in the screen.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display-matrix-text.xml&amp;lt;/tt&amp;gt;: An OSGText &amp;quot;model&amp;quot;, used as a baseline for the texts on the screen. Compare to &amp;lt;tt&amp;gt;README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Nasal''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;: This is the main [[Nasal]] script file to be edited by the ''user'' of the CDU Nasal framework.&lt;br /&gt;
* &amp;lt;tt&amp;gt;cdu_page_framework.nas&amp;lt;/tt&amp;gt;: This is the main file of the CDU framework. It defines the main ''classes'' used for the CDU.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;: This file contains the Nasal relevant for the dispaly matrix. This code might be useful for other complex screen-based instruments.&lt;br /&gt;
* &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;: This file contains functions which I found useful for my project, but which are totally generic and could be used for other stuff as well.&lt;br /&gt;
* &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;: This file contains a rudimentary timer ''class'' and an example of how to incorporate this with a generic class for an instrument button, allowing the button to call different Nasal scripts, depending on how long it has been pressed. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;README&amp;lt;/tt&amp;gt;: Well, a readme.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Loading a CDU into an Aircraft ==&lt;br /&gt;
Here is how the CDU is loaded into the Boeing 777-200:&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;777-22ER-set.xml&amp;lt;/tt&amp;gt; the Nasal node is expanded as follows:&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- generic for the CDU --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/helping_functions.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/timer.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/cdu_page_framework.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;nowiki&amp;gt;&amp;lt;!-- specific for the B777 --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/b777_cdu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
Note the difference in the framework files and the actual ''instance'' used for this aircraft. To code pages for the CDU, one would normally not have to mess with the framework files. [[User:Hcc23|Hcc23]]&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Somewhere in the actual 3D model of the aircraft the &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; for the 3D model of the CDU has to be loaded. I haven't looked for that yet as that was already done for the 777-200. [[User:Hcc23|Hcc23]] 14:42, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== 3D Graphics ==&lt;br /&gt;
The 3D model resides in the file '''&amp;lt;tt&amp;gt;$FGDATA/Models/Cockpit/Instruments/CDU/cdu.ac&amp;lt;/tt&amp;gt;'''. This is a [[AC3D]] file format, but it should be importable by [[Blender]].&lt;br /&gt;
{|&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| [[File:CDU_3D_wireframe.png|thumb|270px|The wireframe of the 3D model and the corresponding coordinate system. ATTENTION: the axis are not right: RED is +X, GREEN is +Z, BLUE is -Y !]]&lt;br /&gt;
| [[File:CDU.png|thumb|270px|The texture of the CDU, a 512x512 PNG bitmap.]]&lt;br /&gt;
| [[File:CDU_3D_textures.png|thumb|270px|The resulting 3D model, after the textures have been added.]]&lt;br /&gt;
|}&lt;br /&gt;
The model also specifies the model internal coordinate system. It is indicated in the pictures through the corresponding axis: X (red), Y (green), and Z (blue). The origin of this coordinate system seems to coincide with the geometric center of the back plane of the [[CDU]], i.e. the YZ-plane is coplanar with the back of the [[CDU]]. The unit of the coordinate system is the SI unit ''Meter''.&lt;br /&gt;
&lt;br /&gt;
The 3D model has bindings defined to each button. So when a certain button is clicked, something happens. Right now most buttons are only used&lt;br /&gt;
to open other [[CDU]]-pages.&lt;br /&gt;
&lt;br /&gt;
=== The Screen of the CDU ===&lt;br /&gt;
With respect to the model coordinate frame, the screen is the rectangle given by:&lt;br /&gt;
&lt;br /&gt;
  Top edge:   z= 0.111, x=0.004&lt;br /&gt;
  Lower edge: z= 0.019, x=0.004&lt;br /&gt;
  Left edge:  y=-0.051, x=0.004&lt;br /&gt;
  Right edge: y= 0.051, x=0.004&lt;br /&gt;
&lt;br /&gt;
= The Code Framework =&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= The CDU Screen = &lt;br /&gt;
One of the major problems of the CDU is the representation of the actual screen. According to the Honeywell manual, the CDU utilized by Boeing has a fixed setup.&lt;br /&gt;
&lt;br /&gt;
== Details of the (LCD) Screen ==&lt;br /&gt;
The LCD has '''14 lines''' with a total of '''24 characters per line'''. The page format is formatted as follows:&lt;br /&gt;
&lt;br /&gt;
* Title Field: The top line of the display area. Id identifies the subject or title of the data displayed on the page in view. It also identifies page number and the number of pages in series, e.g., &amp;lt;tt&amp;gt;1/2&amp;lt;/tt&amp;gt; identifies a page as the first in a series of two pages.&lt;br /&gt;
* Left Field: 6 pairs of lines, 11 characters per line. It extends from the left side of the screen to the center. The pilot has access to one line of each pair through a LSK (Line-Select Key) on the left side of the CDU. A line pair is made up of a label and a data line.&lt;br /&gt;
* Right Field: This field is similar to the left field, extending from the center of the screen to the right side. Pilot access is available by a LSK on the right side. &lt;br /&gt;
* Scratchpad: The bottom line of the display screen. This line displays alphanumeric data or messages. Data can be entered with the alphanumeric keys or the LSK, or by the FMC. Scratchpad entry cannot, normally, be made with a FMC message in the scratchpad. Scratchpad entries are independent of page selection, and remain until cleared even when page changes occur. Scratchpad data entries and erases affect only the associated CDU. Messages can appear and be erased on both CDUs simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Internal Representation ==&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The utilizes display matrix, showing the text bounding boxes for clarity.]]&lt;br /&gt;
As the screen has a &amp;quot;fixed&amp;quot; resolution, internally the screen is represented as a 14-by-24(-by-2) matrix. The zero-indexed matrix is held in the property tree:&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal double-type variable (although it is only integers).&lt;br /&gt;
&lt;br /&gt;
The style of the char is encoded via a binary key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt;  7&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name (used in the Nasal code for the CDU), which is resolved into a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
the first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;). The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet implemented. [[User:Hcc23|Hcc23]] 14:01, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Nasal Code ==&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
== XML Code ==&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== Generating the offset code ===&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= The Property Tree =&lt;br /&gt;
&lt;br /&gt;
The [[CDU]] also has some properties in the general [[FlightGear]] [[Property Tree]].&lt;br /&gt;
In general it is located in &amp;lt;code&amp;gt;/instrumentation/cdu/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= A Brief History of the Boeing CDU in FlightGear =&lt;br /&gt;
Find some more information on the [[CDU]] at these pages:&lt;br /&gt;
* [[CDU]]&lt;br /&gt;
* [[Howto: Implement a Control Display Unit]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30893</id>
		<title>Howto:Coding a Boeing CDU</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30893"/>
		<updated>2011-04-08T18:42:22Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* Finding the Sources */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
[[User:Gijs|Gijs]] has started an effort to bring a generic Boeing [[CDU]] to [[FlightGear]]. This page tries to describe the coding for this effort.&lt;br /&gt;
&lt;br /&gt;
= The Sources =&lt;br /&gt;
The [[CDU]] currently resides in '''$FGDATA/Aircraft/Instruments-3d/cdu/'''.&lt;br /&gt;
&lt;br /&gt;
'''Graphics''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.ac&amp;lt;/tt&amp;gt;: This is a [[AC3D]] file, describing the 3D outline of the CDU model.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_brown.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_grey.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
&lt;br /&gt;
'''XML''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;: This is the main [[XML]] file, providing the direct interface between the 3D model and the code. This file also defines the keypress interactions and the positioning of the text to be displayed in the screen.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display-matrix-text.xml&amp;lt;/tt&amp;gt;: An OSGText &amp;quot;model&amp;quot;, used as a baseline for the texts on the screen. Compare to &amp;lt;tt&amp;gt;README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''Nasal''':&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_cdu.nas&amp;lt;/tt&amp;gt;: This is the main [[Nasal]] script file to be edited by the ''user'' of the CDU Nasal framework.&lt;br /&gt;
* &amp;lt;tt&amp;gt;cdu_page_framework.nas&amp;lt;/tt&amp;gt;: This is the main file of the CDU framework. It defines the main ''classes'' used for the CDU.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;: This file contains the Nasal relevant for the dispaly matrix. This code might be useful for other complex screen-based instruments.&lt;br /&gt;
* &amp;lt;tt&amp;gt;helping_functions.nas&amp;lt;/tt&amp;gt;: This file contains functions which I found useful for my project, but which are totally generic and could be used for other stuff as well.&lt;br /&gt;
* &amp;lt;tt&amp;gt;timer.nas&amp;lt;/tt&amp;gt;: This file contains a rudimentary timer ''class'' and an example of how to incorporate this with a generic class for an instrument button, allowing the button to call different Nasal scripts, depending on how long it has been pressed. &lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;README&amp;lt;/tt&amp;gt;: Well, a readme.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Loading a CDU into an Aircraft ==&lt;br /&gt;
Here is how the CDU is loaded into the Boeing 777-200:&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;777-22ER-set.xml&amp;lt;/tt&amp;gt; the Nasal node is expanded as follows:&lt;br /&gt;
  &amp;lt;nasal&amp;gt;&lt;br /&gt;
        ...&lt;br /&gt;
        &amp;lt;cdu&amp;gt;&lt;br /&gt;
  	    &amp;lt;nowiki&amp;gt;&amp;lt;!-- generic for the CDU --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/helping_functions.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/timer.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/cdu_page_framework.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
            &amp;lt;nowiki&amp;gt;&amp;lt;!-- specific for the B777 --&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
            &amp;lt;file&amp;gt;Aircraft/Instruments-3d/cdu/b777_cdu.nas&amp;lt;/file&amp;gt;&lt;br /&gt;
        &amp;lt;/cdu&amp;gt;&lt;br /&gt;
  &amp;lt;/nasal&amp;gt;&lt;br /&gt;
Note the difference in the framework files and the actual ''instance'' used for this aircraft. To code pages for the CDU, one would normally not have to mess with the framework files. [[User:Hcc23|Hcc23]]&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' Somewhere in the actual 3D model of the aircraft the &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; for the 3D model of the CDU has to be loaded. I haven't looked for that yet as that was already done for the 777-200. [[User:Hcc23|Hcc23]] 14:42, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
== 3D Graphics ==&lt;br /&gt;
The 3D model resides in the file '''&amp;lt;tt&amp;gt;$FGDATA/Models/Cockpit/Instruments/CDU/cdu.ac&amp;lt;/tt&amp;gt;'''. This is a [[AC3D]] file format, but it should be importable by [[Blender]].&lt;br /&gt;
{|&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| [[File:CDU_3D_wireframe.png|thumb|270px|The wireframe of the 3D model and the corresponding coordinate system. ATTENTION: the axis are not right: RED is +X, GREEN is +Z, BLUE is -Y !]]&lt;br /&gt;
| [[File:CDU.png|thumb|270px|The texture of the CDU, a 512x512 PNG bitmap.]]&lt;br /&gt;
| [[File:CDU_3D_textures.png|thumb|270px|The resulting 3D model, after the textures have been added.]]&lt;br /&gt;
|}&lt;br /&gt;
The model also specifies the model internal coordinate system. It is indicated in the pictures through the corresponding axis: X (red), Y (green), and Z (blue). The origin of this coordinate system seems to coincide with the geometric center of the back plane of the [[CDU]], i.e. the YZ-plane is coplanar with the back of the [[CDU]]. The unit of the coordinate system is the SI unit ''Meter''.&lt;br /&gt;
&lt;br /&gt;
The 3D model has bindings defined to each button. So when a certain button is clicked, something happens. Right now most buttons are only used&lt;br /&gt;
to open other [[CDU]]-pages.&lt;br /&gt;
&lt;br /&gt;
=== The Screen of the CDU ===&lt;br /&gt;
With respect to the model coordinate frame, the screen is the rectangle given by:&lt;br /&gt;
&lt;br /&gt;
  Top edge:   z= 0.111, x=0.004&lt;br /&gt;
  Lower edge: z= 0.019, x=0.004&lt;br /&gt;
  Left edge:  y=-0.051, x=0.004&lt;br /&gt;
  Right edge: y= 0.051, x=0.004&lt;br /&gt;
&lt;br /&gt;
= The CDU Screen = &lt;br /&gt;
One of the major problems of the CDU is the representation of the actual screen. According to the Honeywell manual, the CDU utilized by Boeing has a fixed setup.&lt;br /&gt;
&lt;br /&gt;
== Details of the (LCD) Screen ==&lt;br /&gt;
The LCD has '''14 lines''' with a total of '''24 characters per line'''. The page format is formatted as follows:&lt;br /&gt;
&lt;br /&gt;
* Title Field: The top line of the display area. Id identifies the subject or title of the data displayed on the page in view. It also identifies page number and the number of pages in series, e.g., &amp;lt;tt&amp;gt;1/2&amp;lt;/tt&amp;gt; identifies a page as the first in a series of two pages.&lt;br /&gt;
* Left Field: 6 pairs of lines, 11 characters per line. It extends from the left side of the screen to the center. The pilot has access to one line of each pair through a LSK (Line-Select Key) on the left side of the CDU. A line pair is made up of a label and a data line.&lt;br /&gt;
* Right Field: This field is similar to the left field, extending from the center of the screen to the right side. Pilot access is available by a LSK on the right side. &lt;br /&gt;
* Scratchpad: The bottom line of the display screen. This line displays alphanumeric data or messages. Data can be entered with the alphanumeric keys or the LSK, or by the FMC. Scratchpad entry cannot, normally, be made with a FMC message in the scratchpad. Scratchpad entries are independent of page selection, and remain until cleared even when page changes occur. Scratchpad data entries and erases affect only the associated CDU. Messages can appear and be erased on both CDUs simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Internal Representation ==&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The utilizes display matrix, showing the text bounding boxes for clarity.]]&lt;br /&gt;
As the screen has a &amp;quot;fixed&amp;quot; resolution, internally the screen is represented as a 14-by-24(-by-2) matrix. The zero-indexed matrix is held in the property tree:&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal double-type variable (although it is only integers).&lt;br /&gt;
&lt;br /&gt;
The style of the char is encoded via a binary key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt;  7&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name (used in the Nasal code for the CDU), which is resolved into a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
the first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;). The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet implemented. [[User:Hcc23|Hcc23]] 14:01, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Nasal Code ==&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
== XML Code ==&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== Generating the offset code ===&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= The Property Tree =&lt;br /&gt;
&lt;br /&gt;
The [[CDU]] also has some properties in the general [[FlightGear]] [[Property Tree]].&lt;br /&gt;
In general it is located in &amp;lt;code&amp;gt;/instrumentation/cdu/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= A Brief History of the Boeing CDU in FlightGear =&lt;br /&gt;
Find some more information on the [[CDU]] at these pages:&lt;br /&gt;
* [[CDU]]&lt;br /&gt;
* [[Howto: Implement a Control Display Unit]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30892</id>
		<title>Howto:Coding a Boeing CDU</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30892"/>
		<updated>2011-04-08T18:23:29Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* The CDU Screen */  f&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
[[User:Gijs|Gijs]] has started an effort to bring a generic Boeing [[CDU]] to [[FlightGear]]. This page tries to describe the coding for this effort.&lt;br /&gt;
&lt;br /&gt;
= Finding the Sources =&lt;br /&gt;
The [[CDU]] currently resides in '''$FGDATA/Aircraft/Instruments-3d/cdu/'''.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.ac&amp;lt;/tt&amp;gt;: This is a [[AC3D]] file, describing the 3D outline of the CDU model.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.nas&amp;lt;/tt&amp;gt;: This is a [[Nasal]] script file.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;: This is a [[XML]] file, providing the direct interface between the 3D model and the code.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_brown.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_grey.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display-text-value.xml&amp;lt;/tt&amp;gt;: An OSGText &amp;quot;model&amp;quot;, used to display the texts on the screen&lt;br /&gt;
* &amp;lt;tt&amp;gt;README&amp;lt;/tt&amp;gt;: Well, a readme.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3D Graphics ==&lt;br /&gt;
The 3D model resides in the file '''&amp;lt;tt&amp;gt;$FGDATA/Models/Cockpit/Instruments/CDU/cdu.ac&amp;lt;/tt&amp;gt;'''. This is a [[AC3D]] file format, but it should be importable by [[Blender]].&lt;br /&gt;
{|&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| [[File:CDU_3D_wireframe.png|thumb|270px|The wireframe of the 3D model and the corresponding coordinate system. ATTENTION: the axis are not right: RED is +X, GREEN is +Z, BLUE is -Y !]]&lt;br /&gt;
| [[File:CDU.png|thumb|270px|The texture of the CDU, a 512x512 PNG bitmap.]]&lt;br /&gt;
| [[File:CDU_3D_textures.png|thumb|270px|The resulting 3D model, after the textures have been added.]]&lt;br /&gt;
|}&lt;br /&gt;
The model also specifies the model internal coordinate system. It is indicated in the pictures through the corresponding axis: X (red), Y (green), and Z (blue). The origin of this coordinate system seems to coincide with the geometric center of the back plane of the [[CDU]], i.e. the YZ-plane is coplanar with the back of the [[CDU]]. The unit of the coordinate system is the SI unit ''Meter''.&lt;br /&gt;
&lt;br /&gt;
The 3D model has bindings defined to each button. So when a certain button is clicked, something happens. Right now most buttons are only used&lt;br /&gt;
to open other [[CDU]]-pages.&lt;br /&gt;
&lt;br /&gt;
=== The Screen of the CDU ===&lt;br /&gt;
With respect to the model coordinate frame, the screen is the rectangle given by:&lt;br /&gt;
&lt;br /&gt;
  Top edge:   z= 0.111, x=0.004&lt;br /&gt;
  Lower edge: z= 0.019, x=0.004&lt;br /&gt;
  Left edge:  y=-0.051, x=0.004&lt;br /&gt;
  Right edge: y= 0.051, x=0.004&lt;br /&gt;
&lt;br /&gt;
= The CDU Screen = &lt;br /&gt;
One of the major problems of the CDU is the representation of the actual screen. According to the Honeywell manual, the CDU utilized by Boeing has a fixed setup.&lt;br /&gt;
&lt;br /&gt;
== Details of the (LCD) Screen ==&lt;br /&gt;
The LCD has '''14 lines''' with a total of '''24 characters per line'''. The page format is formatted as follows:&lt;br /&gt;
&lt;br /&gt;
* Title Field: The top line of the display area. Id identifies the subject or title of the data displayed on the page in view. It also identifies page number and the number of pages in series, e.g., &amp;lt;tt&amp;gt;1/2&amp;lt;/tt&amp;gt; identifies a page as the first in a series of two pages.&lt;br /&gt;
* Left Field: 6 pairs of lines, 11 characters per line. It extends from the left side of the screen to the center. The pilot has access to one line of each pair through a LSK (Line-Select Key) on the left side of the CDU. A line pair is made up of a label and a data line.&lt;br /&gt;
* Right Field: This field is similar to the left field, extending from the center of the screen to the right side. Pilot access is available by a LSK on the right side. &lt;br /&gt;
* Scratchpad: The bottom line of the display screen. This line displays alphanumeric data or messages. Data can be entered with the alphanumeric keys or the LSK, or by the FMC. Scratchpad entry cannot, normally, be made with a FMC message in the scratchpad. Scratchpad entries are independent of page selection, and remain until cleared even when page changes occur. Scratchpad data entries and erases affect only the associated CDU. Messages can appear and be erased on both CDUs simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Internal Representation ==&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The utilizes display matrix, showing the text bounding boxes for clarity.]]&lt;br /&gt;
As the screen has a &amp;quot;fixed&amp;quot; resolution, internally the screen is represented as a 14-by-24(-by-2) matrix. The zero-indexed matrix is held in the property tree:&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal double-type variable (although it is only integers).&lt;br /&gt;
&lt;br /&gt;
The style of the char is encoded via a binary key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt;  7&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name (used in the Nasal code for the CDU), which is resolved into a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
the first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;). The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet implemented. [[User:Hcc23|Hcc23]] 14:01, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Nasal Code ==&lt;br /&gt;
The [[Nasal]] code for the display matrix is mainly held in &amp;lt;tt&amp;gt;display_matrix.nas&amp;lt;/tt&amp;gt;. &lt;br /&gt;
&lt;br /&gt;
== XML Code ==&lt;br /&gt;
The [[XML]] side of the display matrix comes in multiple parts. &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; contains all the [[XML]] code for the CDU.&lt;br /&gt;
Other than loading the 3D model and defining the button names, &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; also interfaces with [[osgtext]] to actually display text in the 3D model.&lt;br /&gt;
&lt;br /&gt;
In &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt; you will find sections like this one:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;model&amp;gt;&lt;br /&gt;
  	&amp;lt;path&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/path&amp;gt;&lt;br /&gt;
  	&amp;lt;overlay&amp;gt;&lt;br /&gt;
  		&amp;lt;params&amp;gt;&lt;br /&gt;
  			&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&lt;br /&gt;
  		&amp;lt;/params&amp;gt;&lt;br /&gt;
  		&amp;lt;offsets&amp;gt;&lt;br /&gt;
  			&amp;lt;x-m&amp;gt;0.005&amp;lt;/x-m&amp;gt;&lt;br /&gt;
  			&amp;lt;y-m&amp;gt;-0.044&amp;lt;/y-m&amp;gt;&lt;br /&gt;
  			&amp;lt;z-m&amp;gt;0.103&amp;lt;/z-m&amp;gt;&lt;br /&gt;
  		&amp;lt;/offsets&amp;gt;&lt;br /&gt;
  	&amp;lt;/overlay&amp;gt;&lt;br /&gt;
  &amp;lt;/model&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This section defines which node of the matrix to display, indicated by &amp;lt;tt&amp;gt;&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;/instrumentation/cdu/display/row-0/col-0/char&amp;lt;/property&amp;gt;&amp;lt;/tt&amp;gt; for the (0,0) node of the matrix, i.e. to first character in the topmost line.&lt;br /&gt;
&lt;br /&gt;
This [[XML]] section expands on &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt; which gives some underlying structure. For more details on this, please consult &amp;lt;tt&amp;gt;$FGDATA/Docs/README.osgtext&amp;lt;/tt&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' I haven't completely understood how this &amp;lt;tt&amp;gt;&amp;lt;overlay /&amp;gt;&amp;lt;/tt&amp;gt; node actually works, but this setup does what I want it to do. Please feel free to change and explain it here. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' As mentioned above, the style information is not yet implemented. I would like to put that into the [[XML]] in &amp;lt;tt&amp;gt;Aircraft/Instruments-3d/cdu/display_matrix_text.xml&amp;lt;/tt&amp;gt;, but I don't know how to do conditionals in XML. [[User:Hcc23|Hcc23]] 14:23, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
=== Generating the offset code ===&lt;br /&gt;
As you might have figured, there is a lot of identical XML code, just differing in the offset parameters and the row and column index. To make life easier I have written this Matlab script to auto-generate these sections:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
  clear all, close all, clc&lt;br /&gt;
  &lt;br /&gt;
  %% Parameters&lt;br /&gt;
  % These are to be set by the user&lt;br /&gt;
  &lt;br /&gt;
  FILENAME = 'autocoded.xml';&lt;br /&gt;
  &lt;br /&gt;
  ROWS = 14;&lt;br /&gt;
  COLS = 24;&lt;br /&gt;
  &lt;br /&gt;
  TOP = 0.106; % z-axis&lt;br /&gt;
  BOTTOM = 0.024; % z-axis&lt;br /&gt;
  LEFT = -0.046; % y-axis&lt;br /&gt;
  RIGHT = 0.046; % y-axis&lt;br /&gt;
  &lt;br /&gt;
  ELEV = 0.005; % x-axis&lt;br /&gt;
  &lt;br /&gt;
  TEMPLATE = 'Aircraft/Instruments-3d/cdu/display_matrix_text.xml';&lt;br /&gt;
  &lt;br /&gt;
  %% Creating the printout&lt;br /&gt;
  &lt;br /&gt;
  fid = fopen(FILENAME,'wb');&lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  width_of_screen = abs(RIGHT-LEFT);&lt;br /&gt;
  hight_of_screen = abs(TOP-BOTTOM);&lt;br /&gt;
  &lt;br /&gt;
  delta_col = width_of_screen/COLS;&lt;br /&gt;
  delta_row = hight_of_screen/ROWS;&lt;br /&gt;
  &lt;br /&gt;
  x_off = ELEV;&lt;br /&gt;
  z_off = TOP - 0.5*delta_row; &lt;br /&gt;
  y_off_zero = LEFT + 0.5*delta_col;  &lt;br /&gt;
  &lt;br /&gt;
  &lt;br /&gt;
  for row = 0:1:ROWS-1&lt;br /&gt;
      y_off = y_off_zero;&lt;br /&gt;
      for col = 0:1:COLS-1&lt;br /&gt;
                       &lt;br /&gt;
          propertyPath = sprintf('/instrumentation/cdu/display/row-%d/col-%d/char',row,col);&lt;br /&gt;
          &lt;br /&gt;
          fprintf(fid,[...&lt;br /&gt;
          '&amp;lt;model&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;path&amp;gt;%s&amp;lt;/path&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;overlay&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;params&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;property type=&amp;quot;string&amp;quot;&amp;gt;%s&amp;lt;/property&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/params&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;offsets&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;x-m&amp;gt;%.3f&amp;lt;/x-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;y-m&amp;gt;%.3f&amp;lt;/y-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t\t&amp;lt;z-m&amp;gt;%.3f&amp;lt;/z-m&amp;gt;\n',...&lt;br /&gt;
          '\t\t&amp;lt;/offsets&amp;gt;\n',...&lt;br /&gt;
          '\t&amp;lt;/overlay&amp;gt;\n',...&lt;br /&gt;
          '&amp;lt;/model&amp;gt;\n',...&lt;br /&gt;
          ],...&lt;br /&gt;
          TEMPLATE,...&lt;br /&gt;
          propertyPath,...&lt;br /&gt;
          x_off,y_off,z_off);&lt;br /&gt;
          &lt;br /&gt;
          y_off = y_off + delta_col;&lt;br /&gt;
          &lt;br /&gt;
      end&lt;br /&gt;
      z_off = z_off - delta_row;&lt;br /&gt;
  end&lt;br /&gt;
  &lt;br /&gt;
  fclose(fid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
= The Property Tree =&lt;br /&gt;
&lt;br /&gt;
The [[CDU]] also has some properties in the general [[FlightGear]] [[Property Tree]].&lt;br /&gt;
In general it is located in &amp;lt;code&amp;gt;/instrumentation/cdu/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= A Brief History of the Boeing CDU in FlightGear =&lt;br /&gt;
Find some more information on the [[CDU]] at these pages:&lt;br /&gt;
* [[CDU]]&lt;br /&gt;
* [[Howto: Implement a Control Display Unit]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
	<entry>
		<id>https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30891</id>
		<title>Howto:Coding a Boeing CDU</title>
		<link rel="alternate" type="text/html" href="https://wiki.flightgear.org/w/index.php?title=Howto:Coding_a_Boeing_CDU&amp;diff=30891"/>
		<updated>2011-04-08T18:01:31Z</updated>

		<summary type="html">&lt;p&gt;Hcc23: /* The CDU Screen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{WIP|[[User:Hcc23|Hcc23]] is working on this. Find him in the FG IRC channel to discuss this page.}}&lt;br /&gt;
&lt;br /&gt;
[[User:Gijs|Gijs]] has started an effort to bring a generic Boeing [[CDU]] to [[FlightGear]]. This page tries to describe the coding for this effort.&lt;br /&gt;
&lt;br /&gt;
= Finding the Sources =&lt;br /&gt;
The [[CDU]] currently resides in '''$FGDATA/Aircraft/Instruments-3d/cdu/'''.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.ac&amp;lt;/tt&amp;gt;: This is a [[AC3D]] file, describing the 3D outline of the CDU model.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.nas&amp;lt;/tt&amp;gt;: This is a [[Nasal]] script file.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing.xml&amp;lt;/tt&amp;gt;: This is a [[XML]] file, providing the direct interface between the 3D model and the code.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_brown.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;boeing_grey.png&amp;lt;/tt&amp;gt;: A texture bitmap.&lt;br /&gt;
* &amp;lt;tt&amp;gt;display-text-value.xml&amp;lt;/tt&amp;gt;: An OSGText &amp;quot;model&amp;quot;, used to display the texts on the screen&lt;br /&gt;
* &amp;lt;tt&amp;gt;README&amp;lt;/tt&amp;gt;: Well, a readme.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== 3D Graphics ==&lt;br /&gt;
The 3D model resides in the file '''&amp;lt;tt&amp;gt;$FGDATA/Models/Cockpit/Instruments/CDU/cdu.ac&amp;lt;/tt&amp;gt;'''. This is a [[AC3D]] file format, but it should be importable by [[Blender]].&lt;br /&gt;
{|&lt;br /&gt;
|-valign=&amp;quot;top&amp;quot;&lt;br /&gt;
| [[File:CDU_3D_wireframe.png|thumb|270px|The wireframe of the 3D model and the corresponding coordinate system. ATTENTION: the axis are not right: RED is +X, GREEN is +Z, BLUE is -Y !]]&lt;br /&gt;
| [[File:CDU.png|thumb|270px|The texture of the CDU, a 512x512 PNG bitmap.]]&lt;br /&gt;
| [[File:CDU_3D_textures.png|thumb|270px|The resulting 3D model, after the textures have been added.]]&lt;br /&gt;
|}&lt;br /&gt;
The model also specifies the model internal coordinate system. It is indicated in the pictures through the corresponding axis: X (red), Y (green), and Z (blue). The origin of this coordinate system seems to coincide with the geometric center of the back plane of the [[CDU]], i.e. the YZ-plane is coplanar with the back of the [[CDU]]. The unit of the coordinate system is the SI unit ''Meter''.&lt;br /&gt;
&lt;br /&gt;
The 3D model has bindings defined to each button. So when a certain button is clicked, something happens. Right now most buttons are only used&lt;br /&gt;
to open other [[CDU]]-pages.&lt;br /&gt;
&lt;br /&gt;
=== The Screen of the CDU ===&lt;br /&gt;
With respect to the model coordinate frame, the screen is the rectangle given by:&lt;br /&gt;
&lt;br /&gt;
  Top edge:   z= 0.111, x=0.004&lt;br /&gt;
  Lower edge: z= 0.019, x=0.004&lt;br /&gt;
  Left edge:  y=-0.051, x=0.004&lt;br /&gt;
  Right edge: y= 0.051, x=0.004&lt;br /&gt;
&lt;br /&gt;
= The CDU Screen = &lt;br /&gt;
One of the major problems of the CDU is the representation of the actual screen. According to the Honeywell manual, the CDU utilized by Boeing has a fixed setup.&lt;br /&gt;
&lt;br /&gt;
== Details of the (LCD) Screen ==&lt;br /&gt;
The LCD has '''14 lines''' with a total of '''24 characters per line'''. The page format is formatted as follows:&lt;br /&gt;
&lt;br /&gt;
* Title Field: The top line of the display area. Id identifies the subject or title of the data displayed on the page in view. It also identifies page number and the number of pages in series, e.g., &amp;lt;tt&amp;gt;1/2&amp;lt;/tt&amp;gt; identifies a page as the first in a series of two pages.&lt;br /&gt;
* Left Field: 6 pairs of lines, 11 characters per line. It extends from the left side of the screen to the center. The pilot has access to one line of each pair through a LSK (Line-Select Key) on the left side of the CDU. A line pair is made up of a label and a data line.&lt;br /&gt;
* Right Field: This field is similar to the left field, extending from the center of the screen to the right side. Pilot access is available by a LSK on the right side. &lt;br /&gt;
* Scratchpad: The bottom line of the display screen. This line displays alphanumeric data or messages. Data can be entered with the alphanumeric keys or the LSK, or by the FMC. Scratchpad entry cannot, normally, be made with a FMC message in the scratchpad. Scratchpad entries are independent of page selection, and remain until cleared even when page changes occur. Scratchpad data entries and erases affect only the associated CDU. Messages can appear and be erased on both CDUs simultaneously.&lt;br /&gt;
&lt;br /&gt;
== Internal Representation ==&lt;br /&gt;
[[File:CDU HelloWorld.png|thumb|270px|The utilizes display matrix, showing the text bounding boxes for clarity.]]&lt;br /&gt;
As the screen has a &amp;quot;fixed&amp;quot; resolution, internally the screen is represented as a 14-by-24(-by-2) matrix. The zero-indexed matrix is held in the property tree:&lt;br /&gt;
&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/char   # the character printed on the screen&lt;br /&gt;
 /instrumentation/cdu/display/row-0/col-0/style  # the style or format of the printed screen.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tt&amp;gt;.../char&amp;lt;/tt&amp;gt; is a Nasal string-type variable. &amp;lt;tt&amp;gt;.../style&amp;lt;/tt&amp;gt; is a Nasal double-type variable (although it is only integers).&lt;br /&gt;
&lt;br /&gt;
The style of the char is encoded via a binary key-map:&lt;br /&gt;
&lt;br /&gt;
  # styles binary  	# wmcgLS -&amp;gt; decimal&lt;br /&gt;
  &amp;quot;off&amp;quot;: 	0, 	# 000000    0&lt;br /&gt;
  # small and LARGE types&lt;br /&gt;
  &amp;quot;white&amp;quot;: 	32, 	# 100000 -&amp;gt; 32      # the default style&lt;br /&gt;
  &amp;quot;magenta&amp;quot;: 	16, 	# 010000 -&amp;gt; 16&lt;br /&gt;
  &amp;quot;cyan&amp;quot;: 	8, 	# 001000 -&amp;gt;  8&lt;br /&gt;
  &amp;quot;green&amp;quot;: 	4, 	# 000100 -&amp;gt;  4&lt;br /&gt;
  &amp;quot;WHITE&amp;quot;: 	34, 	# 100010 -&amp;gt; 34 &lt;br /&gt;
  &amp;quot;MAGENTA&amp;quot;: 	18, 	# 010010 -&amp;gt; 18&lt;br /&gt;
  &amp;quot;CYAN&amp;quot;: 	10, 	# 001010 -&amp;gt; 10&lt;br /&gt;
  &amp;quot;GREEN&amp;quot;: 	6, 	# 000110 -&amp;gt;  6&lt;br /&gt;
  # shaded small and shaded LARGE types&lt;br /&gt;
  &amp;quot;white_&amp;quot;: 	33, 	# 100001 -&amp;gt; 33&lt;br /&gt;
  &amp;quot;magenta_&amp;quot;: 	7, 	# 010001 -&amp;gt;  7&lt;br /&gt;
  &amp;quot;cyan_&amp;quot;: 	9, 	# 001001 -&amp;gt;  9&lt;br /&gt;
  &amp;quot;green_&amp;quot;: 	5, 	# 000101 -&amp;gt;  5&lt;br /&gt;
  &amp;quot;WHITE_&amp;quot;: 	35, 	# 100011 -&amp;gt; 35&lt;br /&gt;
  &amp;quot;MAGENTA_&amp;quot;: 	19, 	# 010011 -&amp;gt; 19&lt;br /&gt;
  &amp;quot;CYAN_&amp;quot;: 	11, 	# 001011 -&amp;gt; 11&lt;br /&gt;
  &amp;quot;GREEN_&amp;quot;: 	9, 	# 000111 -&amp;gt;  9&lt;br /&gt;
&lt;br /&gt;
Each style has a name (used in the Nasal code for the CDU), which is resolved into a decimal integer. The integer is defined via a binary key:&lt;br /&gt;
the first group represents the colors: white (&amp;lt;tt&amp;gt;w&amp;lt;/tt&amp;gt;), magenta (&amp;lt;tt&amp;gt;m&amp;lt;/tt&amp;gt;), cyan (&amp;lt;tt&amp;gt;c&amp;lt;/tt&amp;gt;), and green (&amp;lt;tt&amp;gt;g&amp;lt;/tt&amp;gt;). The second group represents the font style: large fonts (&amp;lt;tt&amp;gt;L&amp;lt;/tt&amp;gt;) and a shaded background (&amp;lt;tt&amp;gt;S&amp;lt;/tt&amp;gt;).&lt;br /&gt;
&lt;br /&gt;
This concept is translated into the names of the style: it is the name of the color, all lowercase for small fonts, all uppercase for large fonts, and an attached underscore (&amp;lt;tt&amp;gt;_&amp;lt;/tt&amp;gt;) to indicate the selection of a shaded background.&lt;br /&gt;
&lt;br /&gt;
'''NOTE:''' The styles are currently not yet implemented. [[User:Hcc23|Hcc23]] 14:01, 8 April 2011 (EDT)&lt;br /&gt;
&lt;br /&gt;
= The Property Tree =&lt;br /&gt;
&lt;br /&gt;
The [[CDU]] also has some properties in the general [[FlightGear]] [[Property Tree]].&lt;br /&gt;
In general it is located in &amp;lt;code&amp;gt;/instrumentation/cdu/&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
= A Brief History of the Boeing CDU in FlightGear =&lt;br /&gt;
Find some more information on the [[CDU]] at these pages:&lt;br /&gt;
* [[CDU]]&lt;br /&gt;
* [[Howto: Implement a Control Display Unit]]&lt;/div&gt;</summary>
		<author><name>Hcc23</name></author>
	</entry>
</feed>