diff --git a/Aircraft/Instruments-3d/FG1000/MFDPages/Checklist.svg b/Aircraft/Instruments-3d/FG1000/MFDPages/Checklist.svg index e655a701f..a33ea5e89 100644 --- a/Aircraft/Instruments-3d/FG1000/MFDPages/Checklist.svg +++ b/Aircraft/Instruments-3d/FG1000/MFDPages/Checklist.svg @@ -23,9 +23,9 @@ borderopacity="0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="4" - inkscape:cx="834.55454" - inkscape:cy="123.76123" + inkscape:zoom="2" + inkscape:cx="594.53585" + inkscape:cy="130.11243" inkscape:document-units="px" inkscape:current-layer="ChecklistMainPane" showgrid="true" @@ -966,6 +966,30 @@ id="tspan4745" x="946.75195" y="694.34045">GO TO NEXT CHECKLIST? + * CHECKLIST NOT FINISHED * + * CHECKLIST FINISHED * 0) { + foreach (var group; groups) { + var grp = group.getNode("name", 1).getValue(); + checklists[grp] = {}; + foreach (var chklist; group.getChildren("checklist")) { + var items = []; + var title = chklist.getNode("title", 1).getValue(); + + # Checklists can optionally be broken down into individual pages. + foreach (var pg; chklist.getChildren("page")) { + foreach (var item; pg.getChildren("item")) { + var name = item.getNode("name", 1).getValue(); + var value = item.getNode("value", 1).getValue(); + append(items, { Name : name, Value: value, Checked: 0 }); + } + } + + foreach (var item; chklist.getChildren("item")) { + var name = item.getNode("name", 1).getValue(); + var value = item.getNode("value", 1).getValue(); + append(items, { Name : name, Value: value, Checked: 0 }); + } + + # items now contains a list of all the checklists for + checklists[grp][title] = items; } } + } else { + # Checklist doesn't contain any groups, so try to split into Standard + # and Emergency groups by looking at the checklist titles. - foreach (var item; chklist.getChildren("item")) { - var name = item.getNode("name", 1).getValue(); - var value = item.getNode("value", 1).getValue(); - append(items, { Name : name, Value: value, Checked: 0 }); + foreach (var chklist; checklistprops.getChildren("checklist")) { + var title = chklist.getNode("title", 1).getValue(); + var grp = "Standard"; + var items = []; + if (find("emergency", string.lc(title)) != -1) { + grp = "EMERGENCY"; + } + + # Checklists can optionally be broken down into individual pages. + foreach (var pg; chklist.getChildren("page")) { + foreach (var item; pg.getChildren("item")) { + var name = item.getNode("name", 1).getValue(); + var value = item.getNode("value", 1).getValue(); + append(items, { Name : name, Value: value, Checked: 0 }); + } + } + + foreach (var item; chklist.getChildren("item")) { + var name = item.getNode("name", 1).getValue(); + var value = item.getNode("value", 1).getValue(); + append(items, { Name : name, Value: value, Checked: 0 }); + } + + # items now contains a list of all the checklists for + checklists[grp][title] = items; } - - # items now contains a list of all the checklists for - checklists[grp][title] = items; } return checklists; diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Checklist/Checklist.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Checklist/Checklist.nas index d1a329389..13772b25d 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Checklist/Checklist.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Checklist/Checklist.nas @@ -56,7 +56,7 @@ var Checklist = ); obj.checklistDisplay = ChecklistGroupElement.new( - obj.pageName, + obj, svg, 16, "ScrollTrough", @@ -65,12 +65,14 @@ var Checklist = ); # Other dynamic text elements - obj.addTextElements(["GroupName", "Name", "Next"]); + obj.addTextElements(["GroupName", "Name", "Next", "Finished", "NotFinished"]); # The "Next" element isn't technically dynamic, though we want it to be # highlighted as a text element. We need to set a value for it explicitly, # as it'll be set to an empty string otherwise. obj.setTextElement("Next", "GO TO NEXT CHECKLIST?"); + obj.setTextElement("Finished", "* Checklist Finished *"); + obj.setTextElement("NotFinished", "* CHECKLIST NOT FINISHED *"); # Hide the various groups obj.hideChecklistSelect(); @@ -173,8 +175,33 @@ var Checklist = topMenu : func(device, pg, menuitem) { pg.clearMenu(); pg.resetMenuColors(); + pg.addMenuItem(0, "ENGINE", pg, pg.mfd.EIS.engineMenu); + pg.addMenuItem(2, "MAP", pg, pg.mfd.NavigationMap.mapMenu); + pg.addMenuItem(5, "CHECK", pg, + func(dev, pg, mi) { pg.getController().toggleCurrentItem(); dev.updateMenus(); }, # callback + func(svg, mi) { pg.displayCheckUncheck(svg); } # Display function + ); + pg.addMenuItem(10, "EXIT", pg, + # This should return to the previous page... + func(dev, pg, mi) { dev.selectPage(pg.getMFD().getPage("NavigationMap")); }, + ); + + pg.addMenuItem(11, "EMERGENCY", pg, + func(dev, pg, mi) { pg.getController().selectEmergencyChecklist(); }, # callback + ); + device.updateMenus(); }, + + # Display function for the CHECK/UNCHECK softkey + displayCheckUncheck : func (svg) { + if (me.checklistDisplay.getValue()) { + svg.setText("UNCHECK"); + } else { + svg.setText("CHECK"); + } + svg.setVisible(1); + }, }; @@ -187,11 +214,12 @@ var Checklist = var ChecklistGroupElement = { -new : func (pageName, svg, displaysize, scrollTroughElement=nil, scrollThumbElement=nil, scrollHeight=0, style=nil) +new : func (page, svg, displaysize, scrollTroughElement=nil, scrollThumbElement=nil, scrollHeight=0, style=nil) { var obj = { parents : [ ChecklistGroupElement ], - _pageName : pageName, + _page : page, + _pageName : page.pageName, _svg : svg, _style : style, _scrollTroughElement : nil, @@ -234,20 +262,19 @@ new : func (pageName, svg, displaysize, scrollTroughElement=nil, scrollThumbElem "Both the scroll trough element and the scroll thumb element must be defined, or neither"); if (scrollTroughElement != nil) { - obj._scrollTroughElement = svg.getElementById(pageName ~ scrollTroughElement); - assert(obj._scrollTroughElement != nil, "Unable to find scroll element " ~ pageName ~ scrollTroughElement); + obj._scrollTroughElement = svg.getElementById(obj._pageName ~ scrollTroughElement); + assert(obj._scrollTroughElement != nil, "Unable to find scroll element " ~ obj._pageName ~ scrollTroughElement); } if (scrollThumbElement != nil) { - obj._scrollThumbElement = svg.getElementById(pageName ~ scrollThumbElement); - assert(obj._scrollThumbElement != nil, "Unable to find scroll element " ~ pageName ~ scrollThumbElement); + obj._scrollThumbElement = svg.getElementById(obj._pageName ~ scrollThumbElement); + assert(obj._scrollThumbElement != nil, "Unable to find scroll element " ~ obj._pageName ~ scrollThumbElement); obj._scrollBaseTransform = obj._scrollThumbElement.getTranslation(); } if (style == nil) obj._style = PFD.DefaultStyle; for (var i = 0; i < displaysize; i = i + 1) { - append(obj._elements, PFD.HighlightElement.new(pageName, svg, "ItemSelect" ~ i, i, obj._style)); - #append(obj._elements, PFD.TextElement.new(pageName, svg, highlightElement ~ i, i, obj._style)); + append(obj._elements, PFD.HighlightElement.new(obj._pageName, svg, "ItemSelect" ~ i, i, obj._style)); } return obj; @@ -290,8 +317,8 @@ displayGroup : func () { var middle_element_index = math.ceil(me._size / 2); me._pageIndex = me._crsrIndex - middle_element_index; - if (me._crsrIndex < middle_element_index) { - # Start of list + if ((size(me._values) <= me._size) or (me._crsrIndex < middle_element_index)) { + # Start of list or the list is too short to require scrolling me._pageIndex = 0; } else if (me._crsrIndex > (size(me._values) - middle_element_index - 1)) { # End of list @@ -315,7 +342,7 @@ displayGroup : func () { assert(element != nil, "Unable to find element " ~ name); if (k == "ItemSelect") { - # Display if this is the cursor eleemtn + # Display if this is the cursor element element.setVisible(crsr); } else if (k == "ItemTick") { # Check the box if appropriate @@ -384,6 +411,27 @@ displayGroup : func () { me._scrollBaseTransform[1] + me._scrollHeight * (me._crsrIndex / (size(me._values) -1)) ]); } + + # Indicate whether we're finished with this checklist or not + var finished = me.isComplete(); + me._page.getTextElement("Finished").setVisible(finished); + me._page.getTextElement("NotFinished").setVisible(! finished); + + # Update the softkeys, which will in particular change the CHECK/UNCHECK softkeys + # appropriately. + me._page.device.updateMenus(); +}, + +isComplete : func() { + var finished = 1; + foreach (var entry; me._values) { + if (entry["ItemTick"] == 0) { + finished = 0; + break; + } + } + + return finished; }, # Methods to add dynamic elements to the group. Must be called in the @@ -402,8 +450,8 @@ showCRSR : func() { }, hideCRSR : func() { if (me._crsrEnabled == 0) return; - me.displayGroup(); me._crsrEnabled = 0; + me.displayGroup(); }, setCRSR : func(index) { me._crsrIndex = math.min(index, size(me._values) -1); @@ -423,11 +471,11 @@ isCursorOnDataEntryElement : func() { enterElement : func() { if (me._crsrEnabled == 0) return; - # ENT on an element of the checklist simply toggles the item itself, + # ENT on an element of the checklist checks the box, # indicated by whether the check mark is visible or not. var name = me._pageName ~ "ItemTick" ~ (me._crsrIndex - me._pageIndex); var element = me._svg.getElementById(name); - element.setVisible(! element.getVisible()); + element.setVisible(1); return element.getVisible(); }, getValue : func() { @@ -444,7 +492,13 @@ setValue : func(idx, key, value) { }, clearElement : func() { if (me._crsrEnabled == 0) return; - me._elements[me._crsrIndex - me._pageIndex].clearElement(); + + # CLR on an element of the checklist unchecks the box, + # indicated by whether the check mark is visible or not. + var name = me._pageName ~ "ItemTick" ~ (me._crsrIndex - me._pageIndex); + var element = me._svg.getElementById(name); + element.setVisible(0); + return element.getVisible(); }, incrSmall : func(value) { if (me._crsrEnabled == 0) return; diff --git a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Checklist/ChecklistController.nas b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Checklist/ChecklistController.nas index 2c01ce07b..c27bb9ca1 100644 --- a/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Checklist/ChecklistController.nas +++ b/Aircraft/Instruments-3d/FG1000/Nasal/MFDPages/Checklist/ChecklistController.nas @@ -50,6 +50,10 @@ var ChecklistController = selectItems : func() { me.selectGroup(ChecklistController.UIGROUP.ITEMS); }, + selectNext : func() { + me.selectGroup(ChecklistController.UIGROUP.NEXT); + }, + getSelectedGroup : func() { return me._currentGroup; @@ -85,6 +89,26 @@ var ChecklistController = } }, + selectEmergencyChecklist : func() { + # Select the EMERGENCY checklist group, if available. + var emergency_labels = ["EMERGENCY", "Emergency", "emergency"]; + var group = nil; + foreach (var l; emergency_labels) { + if (me._checklists[l] != nil) { + group = l; + break; + } + } + + if (group != nil) { + me._group_selected = group; + me._list_selected = keys(me._checklists[me._group_selected])[0]; + me._page.hideGroupSelect(); + me._page.displayChecklist(me._group_selected, me._list_selected, me._checklists); + me.selectChecklist(); + } + }, + # Input Handling handleCRSR : func() { me._crsrToggle = (! me._crsrToggle); @@ -129,6 +153,11 @@ var ChecklistController = }, handleFMSOuter : func(value) { if (me._crsrToggle == 1) { + # Manual explicitly documents that _either_ FMS knob may be used to scroll through the checklist. + # However, that means that there is no way to navigate from the checklist itself other + # than to disable and then re-enable the CRSR. Odd. + if (me._currentGroup == ChecklistController.UIGROUP.ITEMS) return me.handleFMSInner(value); + var incr_or_decr = (value > 0) ? 1 : -1; var idx = me._currentGroup + incr_or_decr; if (idx < 0) idx = 0; @@ -164,12 +193,22 @@ var ChecklistController = } if (me._currentGroup == ChecklistController.UIGROUP.ITEMS) { - # Toggle the status of the selected Checklist item + # Check the selected Checklist item + me.checkCurrentItem(); var idx = me._page.checklistDisplay.getCRSR(); - var checked = me._page.checklistDisplay.getValue(); - me._checklists[me._group_selected][me._list_selected][idx]["Checked"] = me._page.checklistDisplay.enterElement(); - me._page.displayChecklist(me._group_selected, me._list_selected, me._checklists); - me._page.checklistDisplay.incrSmall(1); + + if ((idx == (size(me._checklists[me._group_selected][me._list_selected]) -1)) and + me._page.checklistDisplay.isComplete()) { + # If we're right at the end of this checklist then move onto the "Next Checklist" + # button. Manual isn't clear on whether this is only if the checklist is complete, + # but we will assume that is the case. + me.selectNext(); + } else { + # Automatically go to the next item. + me.handleFMSInner(1); + } + + return emesary.Transmitter.ReceiptStatus_Finished; } if (me._currentGroup == ChecklistController.UIGROUP.NEXT) { @@ -182,6 +221,7 @@ var ChecklistController = if (idx < size(lists)) { me._list_selected = lists[idx]; + me._page.checklistDisplay.setCRSR(0); me._page.displayChecklist(me._group_selected, me._list_selected, me._checklists); me.selectItems(); } @@ -194,6 +234,39 @@ var ChecklistController = } }, + handleClear : func() { + if ((me._crsrToggle == 1) and + (me._currentGroup == ChecklistController.UIGROUP.ITEMS)) { + # Uncheck the selected Checklist item + me.clearCurrentItem(); + return emesary.Transmitter.ReceiptStatus_Finished; + } + + return emesary.Transmitter.ReceiptStatus_NotProcessed; + }, + + checkCurrentItem : func() { + me._page.checklistDisplay.enterElement(); + var idx = me._page.checklistDisplay.getCRSR(); + me._checklists[me._group_selected][me._list_selected][idx]["Checked"] = 1; + me._page.displayChecklist(me._group_selected, me._list_selected, me._checklists); + }, + + clearCurrentItem : func() { + me._page.checklistDisplay.clearElement(); + var idx = me._page.checklistDisplay.getCRSR(); + me._checklists[me._group_selected][me._list_selected][idx]["Checked"] = 0; + me._page.displayChecklist(me._group_selected, me._list_selected, me._checklists); + }, + + toggleCurrentItem : func() { + if (me._page.checklistDisplay.getValue()) { + me.clearCurrentItem(); + } else { + me.checkCurrentItem(); + } + }, + # Retrieve the current set of checklists from the system. getChecklists : func() { var notification = notifications.PFDEventNotification.new( diff --git a/Nasal/canvas/PFD/GroupElement.nas b/Nasal/canvas/PFD/GroupElement.nas index 8eeab874e..69745e262 100644 --- a/Nasal/canvas/PFD/GroupElement.nas +++ b/Nasal/canvas/PFD/GroupElement.nas @@ -108,11 +108,11 @@ displayGroup : func () { # In these cases, we let the cursor move to the top or bottom of the list. # Determine the middle element - var middle_element_index = int(me._size / 2); + var middle_element_index = math.ceil(me._size / 2); me._pageIndex = me._crsrIndex - middle_element_index; - if (me._crsrIndex < middle_element_index) { - # Start of list + if ((size(me._values) <= me._size) or (me._crsrIndex < middle_element_index)) { + # Start of list or the list is too short to require scrolling me._pageIndex = 0; } else if (me._crsrIndex > (size(me._values) - middle_element_index - 1)) { # End of list