diff --git a/Docs/README.checklists b/Docs/README.checklists
index 9567e1cff..18cf1db59 100644
--- a/Docs/README.checklists
+++ b/Docs/README.checklists
@@ -7,6 +7,8 @@ the Help->Checklists menu within the simulator.
Tutorials are automatically generated from checklists on startup.
Each checklist is defined as a property tree under /sim/checklists/checklist[n]
+or /sim/checklists/group[n]/checklist[m]
+
with the following tags
- Name of the checklist
@@ -16,17 +18,29 @@ with the following tags
- One or more values for the checklist item, to appear on the right
hand side
- A tutorial marker (displayed when the user presses the ? button)
- This can be easily placed using the Help->Display Tutorial Marker.
+ This can be easily placed using the Help->Display Tutorial Marker.
Contains x-m, y-m, z-m and scale tag.
- Optional standard FlightGear condition node that evaluates when the
checklist item has been completed.
- Zero or more bindings to execute the checklist item. Allows the user
- to have their virtual co-pilot perform the action if they select the
+ to have their virtual co-pilot perform the action if they select the
">" button next to the checklist item.
-
-The tag may be omitted for single-page checklists, with the tags
+
+The tag may be omitted for single-page checklists, with the tags
immediately under the node.
-See the c172p for an example of this in action (Aircraft/c172p/c172-checklists.xml).
+Checklists may be grouped under nodes with a tag decribing the
+group. For example
-
+
+ Emergency
+ ...
+ ...
+
+
+ Normal
+ ...
+ ...
+
+
+See the c172p for an example of this in action (Aircraft/c172p/c172-checklists.xml).
diff --git a/Nasal/checklist.nas b/Nasal/checklist.nas
index 27f852a15..6d29fbbeb 100644
--- a/Nasal/checklist.nas
+++ b/Nasal/checklist.nas
@@ -3,69 +3,80 @@
# Convert checklists into full tutorials.
var convert_checklists = func {
- if ((props.globals.getNode("/sim/checklists") != nil) and
- (props.globals.getNode("/sim/checklists").getChildren("checklist") != nil) and
- (size(props.globals.getNode("/sim/checklists").getChildren("checklist")) > 0) )
- {
- var checklists = props.globals.getNode("/sim/checklists").getChildren("checklist");
- var tutorials = props.globals.getNode("/sim/tutorials", 1);
+ if (props.globals.getNode("/sim/checklists") == nil) return;
- foreach (var ch; checklists) {
- var name = ch.getNode("title", 1).getValue();
- var tutorial = tutorials.getNode("tutorial[" ~ size(tutorials.getChildren("tutorial")) ~ "]", 1);
+ var tutorials = props.globals.getNode("/sim/tutorials", 1);
+ var groups = props.globals.getNode("/sim/checklists").getChildren("group");
+ var checklists = [];
- # Initial high level config
- tutorial.getNode("name", 1).setValue("Checklist: " ~ name);
- var description =
- "Tutorial to run through the " ~
- name ~
- " checklist.\n\nChecklist available through the Help->Checklists menu.\n\n";
-
- var step = tutorial.getNode("step", 1);
- step.getNode("message", 1).setValue("Checklist: " ~ name);
-
- # Now go through each of the checklist items and generate a tutorial step
- # for each.
-
- # Checklist may consist of one or more pages.
- var pages = ch.getChildren("page");
-
- if (size(pages) == 0) {
- # Or no pages at all, in which case we need to create a checklist of one page
- append(pages, ch);
- }
-
- foreach (var page; pages) {
- foreach (var item; page.getChildren("item")) {
- step = tutorial.getNode("step["~ size(tutorial.getChildren("step")) ~ "]", 1);
-
- var msg = item.getNode("name", 1).getValue();
-
- if (size(item.getChildren("value")) > 0) {
- msg = msg ~ " :";
- foreach (var v; item.getChildren("value")) {
- msg = msg ~ " " ~ v.getValue();
- }
- }
-
- step.getNode("message", 1).setValue(msg);
- description = description ~ msg ~ "\n";
-
- if (item.getNode("condition") != nil) {
- var cond = step.getNode("exit", 1).getNode("condition", 1);
- props.copy(item.getNode("condition"), cond);
- }
-
- if (item.getNode("marker") != nil) {
- var marker= step.getNode("marker", 1);
- props.copy(item.getNode("marker"), marker);
- }
-
- }
- }
-
- tutorial.getNode("description", 1).setValue(description);
+ if (size(groups) > 0) {
+ foreach (var grp; groups) {
+ var checks = grp.getChildren("checklist");
+ foreach (var chk; checks) {
+ append(checklists, chk);
+ }
}
+ } else {
+ checklists = props.globals.getNode("/sim/checklists").getChildren("checklist");
+ }
+
+ if (size(checklists) == 0) return;
+
+ foreach (var ch; checklists) {
+ var name = ch.getNode("title", 1).getValue();
+ var tutorial = tutorials.getNode("tutorial[" ~ size(tutorials.getChildren("tutorial")) ~ "]", 1);
+
+ # Initial high level config
+ tutorial.getNode("name", 1).setValue("Checklist: " ~ name);
+ var description =
+ "Tutorial to run through the " ~
+ name ~
+ " checklist.\n\nChecklist available through the Help->Checklists menu.\n\n";
+
+ var step = tutorial.getNode("step", 1);
+ step.getNode("message", 1).setValue("Checklist: " ~ name);
+
+ # Now go through each of the checklist items and generate a tutorial step
+ # for each.
+
+ # Checklist may consist of one or more pages.
+ var pages = ch.getChildren("page");
+
+ if (size(pages) == 0) {
+ # Or no pages at all, in which case we need to create a checklist of one page
+ append(pages, ch);
+ }
+
+ foreach (var page; pages) {
+ foreach (var item; page.getChildren("item")) {
+ step = tutorial.getNode("step["~ size(tutorial.getChildren("step")) ~ "]", 1);
+
+ var msg = item.getNode("name", 1).getValue();
+
+ if (size(item.getChildren("value")) > 0) {
+ msg = msg ~ " :";
+ foreach (var v; item.getChildren("value")) {
+ msg = msg ~ " " ~ v.getValue();
+ }
+ }
+
+ step.getNode("message", 1).setValue(msg);
+ description = description ~ msg ~ "\n";
+
+ if (item.getNode("condition") != nil) {
+ var cond = step.getNode("exit", 1).getNode("condition", 1);
+ props.copy(item.getNode("condition"), cond);
+ }
+
+ if (item.getNode("marker") != nil) {
+ var marker= step.getNode("marker", 1);
+ props.copy(item.getNode("marker"), marker);
+ }
+
+ }
+ }
+
+ tutorial.getNode("description", 1).setValue(description);
}
}
diff --git a/gui/dialogs/checklist.xml b/gui/dialogs/checklist.xml
index 97fb4389b..7069c6cf4 100644
--- a/gui/dialogs/checklist.xml
+++ b/gui/dialogs/checklist.xml
@@ -13,48 +13,129 @@
0) {
+ foreach (var grp; groups) {
+ var name = grp.getNode("name", 1).getValue();
+ var checks = grp.getChildren("checklist");
+ foreach (var chk; checks) {
+ var title = chk.getNode("title", 1).getValue();
+ if (current_group == nil) current_group = name;
+ append(checklists, chk);
+ if (checklist_group[name] == nil) checklist_group[name] = [];
+ append(checklist_group[name], title);
+ }
+ }
+ } else {
+ checklists = props.globals.getNode("/sim/checklists").getChildren("checklist");
+ foreach (var chk; checklists) {
+ var title = chk.getNode("title", 1).getValue();
+ var grp = "Standard";
+ var items = [];
+ if (find("emergency", string.lc(title)) != -1) {
+ grp = "EMERGENCY";
+ }
+
+ if (current_group == nil) current_group = grp;
+
+ if (checklist_group[grp] == nil) checklist_group[grp] = [];
+ append(checklist_group[grp], title);
+ }
+ }
+
if (size(checklists) > 0) {
- if (getprop("sim/gui/dialogs/checklist/selected-checklist") == nil) {
- setprop("sim/gui/dialogs/checklist/selected-checklist", checklists[0].getNode("title", 1).getValue());
- setprop("sim/gui/dialogs/checklist/selected-page", 0);
+ var current_checklist = getprop("sim/gui/dialogs/checklist/selected-checklist");
+ if (current_checklist == nil) {
+ current_checklist = checklists[0].getNode("title", 1).getValue();
+ setprop("sim/gui/dialogs/checklist/selected-checklist", current_checklist);
+ setprop("sim/gui/dialogs/checklist/selected-page", 0);
}
-
- var combo = gui.findElementByName(dlgRoot, "checklist-combo");
- var group = gui.findElementByName(dlgRoot, "checklist-table-group");
-
+
+ foreach (var grp; keys(checklist_group)) {
+ foreach (chklist; checklist_group[grp]) {
+ if (chklist == current_checklist) {
+ setChecklistGroup(grp);
+ }
+ }
+ }
+
+ var combo = gui.findElementByName(dlgRoot, "checklist-group-combo");
+ var idx = 0;
+
+ foreach (var grp_name; keys(checklist_group)) {
+ combo.getChild("value", idx, 1).setValue(grp_name);
+ idx = idx + 1;
+ }
+
+ dlgRoot.setValues({"dialog-name": dlgname, "object-name": "checklist-group-combo"});
+ fgcommand("dialog-update", dlgRoot);
+
+ var group = gui.findElementByName(dlgRoot, "checklist-table-group");
+
var table_count = 0;
-
+
forindex (var idx; checklists) {
var checklist_name = checklists[idx].getNode("title", 1).getValue();
- combo.getChild("value", idx, 1).setValue(checklist_name);
-
+
# Checklist may consist of one or more pages.
var pages = checklists[idx].getChildren("page");
-
+
if (size(pages) == 0) {
# Or no pages at all, in which case we need to create a checklist of one page
append(pages, checklists[idx]);
}
-
- checklist_size[checklist_name] = size(pages);
-
+
+ checklist_size[checklist_name] = size(pages);
+
if (idx == 0) {
+
setprop("/sim/gui/dialogs/checklist/next-available", 1);
setprop("/sim/gui/dialogs/checklist/selected-checklist-max-pages", checklist_size[checklist_name]);
- setprop("/sim/gui/dialogs/checklist/selected-page-text", "1 / " ~ checklist_size[checklist_name]);
+ setprop("/sim/gui/dialogs/checklist/selected-page-text", "1 / " ~ checklist_size[checklist_name]);
}
-
- forindex (var p; pages) {
- var c = pages[p];
+
+ forindex (var p; pages) {
+ var c = pages[p];
var row = 0;
-
+
# Set up a new table, only visible when this checklist is selected.
var table = group.getChild("group", table_count, 1);
table.getNode("row", 1).setValue(0);
@@ -62,29 +143,29 @@
table.getNode("default-padding", 1).setValue(4);
table.getNode("layout", 1).setValue("table");
table.getNode("valign", 1).setValue("top");
-
+
# Set up conditional to only display when the checklist is selected
# and the page is correct.
- var vis = table.getNode("visible", 1).getNode("and", 1);
+ var vis = table.getNode("visible", 1).getNode("and", 1);
var e = vis.getChild("equals", 0, 1);
e.getNode("property", 1).setValue("sim/gui/dialogs/checklist/selected-checklist");
e.getNode("value", 1).setValue(checklists[idx].getNode("title").getValue());
e = vis.getChild("equals", 1, 1);
e.getNode("property", 1).setValue("sim/gui/dialogs/checklist/selected-page");
e.getNode("value", 1).setValue(p);
-
+
var items = c.getChildren("item");
var txtcount = 0;
var btncount = 0;
-
- forindex (var i; items) {
+
+ forindex (var i; items) {
var item = items[i];
var t = table.getChild("text", txtcount, 1);
- txtcount += 1;
+ txtcount += 1;
var values = item.getChildren("value");
-
+
if (size(values) == 0) {
# Single name element with no values. Used as title
t.getNode("halign", 1).setValue("center");
@@ -98,7 +179,7 @@
t.getNode("row", 1).setValue(row);
t.getNode("col", 1).setValue(0);
t.getNode("label", 1).setValue(item.getNode("name", 1).getValue());
-
+
forindex (var v; values) {
var t = table.getChild("text", txtcount, 1);
txtcount += 1;
@@ -106,23 +187,23 @@
t.getNode("row", 1).setValue(row);
if (v > 0) {
# The second row of values can overlap with the
- # first column if required - helps keep the
+ # first column if required - helps keep the
# checklist dialog as compact as possible
t.getNode("col", 1).setValue(0);
t.getNode("colspan", 1).setValue(2);
} else {
t.getNode("col", 1).setValue(1);
}
-
- t.getNode("label", 1).setValue(values[v].getValue());
-
+
+ t.getNode("label", 1).setValue(values[v].getValue());
+
# If there's a complete node, it contains a condition
# that can be checked to ensure the checklist item is
- # complete. We display this item in yellow while the
+ # complete. We display this item in yellow while the
# condition is not met, and green once it is complete.
-
+
var condition = item.getNode("condition");
-
+
if (condition != nil) {
var vis = t.getNode("visible", 1);
props.copy(condition, vis);
@@ -135,39 +216,39 @@
# Now create an amber version for when the condition
# is not met.
t = table.getChild("text", txtcount, 1);
- txtcount += 1;
-
+ txtcount += 1;
+
t.getNode("halign", 1).setValue("right");
t.getNode("row", 1).setValue(row);
if (v > 0) {
# The second row of values can overlap with the
- # first column if required - helps keep the
+ # first column if required - helps keep the
# checklist dialog as compact as possible
t.getNode("col", 1).setValue(0);
t.getNode("colspan", 1).setValue(2);
} else {
t.getNode("col", 1).setValue(1);
}
-
- t.getNode("label", 1).setValue(values[v].getValue());
-
+
+ t.getNode("label", 1).setValue(values[v].getValue());
+
c = t.getNode("color", 1);
c.getNode("red", 1).setValue(1.0);
c.getNode("green", 1).setValue(0.7);
c.getNode("blue", 1).setValue(0.2);
-
+
vis = t.getNode("visible", 1).getNode("not", 1);
- props.copy(condition, vis);
+ props.copy(condition, vis);
}
-
+
# If there is a marker node we display a small
# button that enables the marker.
var marker = item.getNode("marker");
-
+
if ((v == 0) and (marker != nil)) {
var s = marker.getNode("scale");
var scale = s != nil ? s.getValue() : 1;
-
+
var btn = table.getChild("button", btncount, 1);
btncount += 1;
btn.getNode("row", 1).setValue(row);
@@ -184,12 +265,12 @@
marker.getNode("z-m", 1).getValue() ~ ", " ~
scale ~ ");");
}
-
+
# If there's one or more binding nodes we display a
- # small button that executes the binding. Used to
+ # small button that executes the binding. Used to
# demonstrate the checklist item
var bindings = item.getChildren("binding");
-
+
if ((v == 0) and (size(bindings) > 0)) {
var btn = table.getChild("button", btncount, 1);
btncount += 1;
@@ -199,19 +280,19 @@
btn.getNode("pref-height", 1).setValue(20);
btn.getNode("padding", 1).setValue(1);
btn.getNode("legend", 1).setValue(">");
-
+
forindex (var bdg; bindings) {
var binding = btn.getChild("binding", bdg, 1);
props.copy(bindings[bdg], binding);
}
}
-
- row = row + 1;
+
+ row = row + 1;
}
-
+
table_count = table_count + 1;
}
- }
+ }
}
}
@@ -219,8 +300,8 @@
setprop("/sim/gui/dialogs/checklist/selected-checklist-max-pages", checklist_size[s]);
setprop("/sim/gui/dialogs/checklist/selected-page", 0);
setprop("/sim/gui/dialogs/checklist/next-available", 1);
- setprop("/sim/gui/dialogs/checklist/selected-page-text", "1 / " ~ checklist_size[s]);
-
+ setprop("/sim/gui/dialogs/checklist/selected-page-text", "1 / " ~ checklist_size[s]);
+
} else {
var group = gui.findElementByName(dlgRoot, "checklist-table-group");
var table = group.getNode("text", 1);
@@ -230,12 +311,12 @@
table.getNode("layout", 1).setValue("table");
table.getNode("valign", 1).setValue("top");
table.getNode("halign", 1).setValue("center");
- table.getNode("label", 1).setValue("No checklists exist for this aircraft");
+ table.getNode("label", 1).setValue("No checklists exist for this aircraft");
}
-
+
var placeMarker = func(x,y,z,scale) {
var markerN = props.globals.getNode("/sim/model/marker", 1);
-
+
markerN.setValues({
"x/value": x,
"y/value": y,
@@ -243,34 +324,34 @@
"scale/value": scale,
"arrow-enabled": 1,
});
- }
-
+ };
+
var nextPage = func() {
var currentPage = getprop("/sim/gui/dialogs/checklist/selected-page");
var s = getprop("/sim/gui/dialogs/checklist/selected-checklist");
-
+
if (currentPage < (checklist_size[s] - 1)) {
- setprop("/sim/gui/dialogs/checklist/selected-page", currentPage + 1);
- }
+ setprop("/sim/gui/dialogs/checklist/selected-page", currentPage + 1);
+ }
if (currentPage == (checklist_size[s] - 2)) {
setprop("/sim/gui/dialogs/checklist/next-available", 0);
}
-
- setprop("/sim/gui/dialogs/checklist/selected-page-text", (currentPage + 2) ~ " / " ~ checklist_size[s]);
- }
-
+
+ setprop("/sim/gui/dialogs/checklist/selected-page-text", (currentPage + 2) ~ " / " ~ checklist_size[s]);
+ };
+
var previousPage = func() {
var currentPage = getprop("/sim/gui/dialogs/checklist/selected-page");
-
+
if (currentPage > 0) {
- setprop("/sim/gui/dialogs/checklist/selected-page", currentPage - 1);
- }
-
+ setprop("/sim/gui/dialogs/checklist/selected-page", currentPage - 1);
+ }
+
setprop("/sim/gui/dialogs/checklist/next-available", 1);
- setprop("/sim/gui/dialogs/checklist/selected-page-text", currentPage ~ " / " ~ checklist_size[s]);
- }
-
+ setprop("/sim/gui/dialogs/checklist/selected-page-text", currentPage ~ " / " ~ checklist_size[s]);
+ };
+
var setTransparency = func(updateDialog){
var alpha = (getprop("/sim/gui/dialogs/checklist/transparent") or 0);
dlgRoot.getNode("color/alpha").setValue(1-alpha*0.3);
@@ -280,11 +361,11 @@
fgcommand("dialog-close", n);
fgcommand("dialog-show", n);
}
- }
+ };
setTransparency(0);
-
+
]]>
-
+
+
+ right
+
+
+
+
+ checklist-group-combo
+ /sim/gui/dialogs/checklist/selected-checklist-group
+ false
+ 230
+ fill
+
+ dialog-apply
+ checklist-group-combo
+
+
+ nasal
+
+
+
+
right
@@ -343,19 +448,19 @@
nasal
-
+
-
+
true
-
+
right
@@ -380,32 +485,32 @@
right
-
+
-
+
4filltablechecklist-table-group
-
+
5fillhbox
-
+
/sim/gui/dialogs/checklist/selected-checklist-max-pages1
-
+
true
-
+
-
+
true
-
+
center
@@ -454,7 +559,7 @@
true
-
+
-
+