# Copyright 2018 Stuart Buchanan # This file is part of FlightGear. # # FlightGear is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # # FlightGear is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with FlightGear. If not, see . # # Checklist Controller var ChecklistController = { UIGROUP : { GROUP : 0, CHECKLIST: 1, ITEMS : 2, NEXT : 3, }, new : func (page, svg) { var obj = { parents : [ ChecklistController, MFDPageController.new(page) ], _crsrToggle : 0, _recipient : nil, _page : page, _currentGroup : -1, _group_selected : nil, _list_selected : nil, _checklists : nil, }; obj.selectGroup(-1); return obj; }, selectGroup : func() { me.selectGroup(ChecklistController.UIGROUP.GROUP) }, selectChecklist : func() { me.selectGroup(ChecklistController.UIGROUP.CHECKLIST); }, selectItems : func() { me.selectGroup(ChecklistController.UIGROUP.ITEMS); }, selectNext : func() { me.selectGroup(ChecklistController.UIGROUP.NEXT); }, getSelectedGroup : func() { return me._currentGroup; }, selectGroup : func(grp) { me._page.hideGroupSelect(); me._page.hideChecklistSelect(); me._currentGroup = grp; if (grp == ChecklistController.UIGROUP.GROUP) { me._page.highlightTextElement("GroupName"); } else { me._page.unhighlightTextElement("GroupName"); } if (grp == ChecklistController.UIGROUP.CHECKLIST) { me._page.highlightTextElement("Name"); } else { me._page.unhighlightTextElement("Name"); } if (grp == ChecklistController.UIGROUP.ITEMS) { me._page.checklistDisplay.showCRSR(); } else { me._page.checklistDisplay.hideCRSR(); } if (grp == ChecklistController.UIGROUP.NEXT) { me._page.highlightTextElement("Next"); } else { me._page.unhighlightTextElement("Next"); } }, selectEmergencyChecklist : func() { if (me._checklist == nil) return; # 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() { # If there are no checklists then we don't allow the CRSR to be enabled as # there's nothing to do. if (me._checklists == nil) return emesary.Transmitter.ReceiptStatus_Finished; me._crsrToggle = (! me._crsrToggle); if (me._crsrToggle) { me.selectGroup(0); } else { me.selectGroup(-1); } return emesary.Transmitter.ReceiptStatus_Finished; }, handleFMSInner : func(value) { if (me._crsrToggle == 1) { # Either display the select group or scroll through whatever is the current list if (me._currentGroup == ChecklistController.UIGROUP.GROUP) { if (me._page.isGroupSelectVisible()) { me._page.checklistGroupSelect.incrSmall(value); } else { me._page.displayGroupSelect(); me._page.unhighlightTextElement("GroupName"); } } if (me._currentGroup == ChecklistController.UIGROUP.CHECKLIST) { if (me._page.isChecklistSelectVisible()) { me._page.checklistSelect.incrSmall(value); } else { me._page.displayChecklistSelect(); me._page.unhighlightTextElement("Name"); } } if (me._currentGroup == ChecklistController.UIGROUP.ITEMS) { me._page.checklistDisplay.incrSmall(value); } return emesary.Transmitter.ReceiptStatus_Finished; } else { # Pass to the page group controller to display and scroll through the page group menu return me._page.mfd.SurroundController.handleFMSInner(value); } }, 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; if (idx > (size(ChecklistController.UIGROUP) -1)) idx = size(ChecklistController.UIGROUP) -1; me.selectGroup(idx); return emesary.Transmitter.ReceiptStatus_Finished; } else { # Pass to the page group controller to display and scroll through the page group menu return me._page.mfd.SurroundController.handleFMSOuter(value); } }, handleEnter : func(value) { if (me._crsrToggle == 1) { if (me._checklists ==nil) return emesary.Transmitter.ReceiptStatus_Finished; if (me._currentGroup == ChecklistController.UIGROUP.GROUP) { # Load the new group, selecting the first checklist in the group me._group_selected = me._page.checklistGroupSelect.getValue(); 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._page.checklistDisplay.setCRSR(0); me.selectChecklist(); return emesary.Transmitter.ReceiptStatus_Finished; } if (me._currentGroup == ChecklistController.UIGROUP.CHECKLIST) { # Load the selected checking from the group me._list_selected = me._page.checklistSelect.getValue(); me._page.hideChecklistSelect(); me._page.displayChecklist(me._group_selected, me._list_selected, me._checklists); me._page.checklistDisplay.setCRSR(0); me.selectItems(); return emesary.Transmitter.ReceiptStatus_Finished; } if (me._currentGroup == ChecklistController.UIGROUP.ITEMS) { # Check the selected Checklist item me.checkCurrentItem(); var idx = me._page.checklistDisplay.getCRSR(); 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) { # Select the next checklist if there's one available var lists = keys(me._checklists[me._group_selected]); var idx = 0; for (i = 0; i < size(lists); i = i +1) { if (lists[i] == me._list_selected) idx = i + 1; } 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(); } return emesary.Transmitter.ReceiptStatus_Finished; } return emesary.Transmitter.ReceiptStatus_NotProcessed; } else { return emesary.Transmitter.ReceiptStatus_NotProcessed; } }, 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( "MFD", me.getDeviceID(), notifications.PFDEventNotification.NavData, {Id: "GetChecklists", Value: nil}); var response = me._transmitter.NotifyAll(notification); if (! me._transmitter.IsFailed(response)) { me._checklists = notification.EventParameter.Value; } me._page.displayChecklist("", "", nil); # Find the first checklist of the first group to display; if ((me._checklists != nil) and size(keys(me._checklists)) != 0) { me._group_selected = keys(me._checklists)[0]; if (size(keys(me._checklists[me._group_selected])) != 0) { me._list_selected = keys(me._checklists[me._group_selected])[0]; me._page.displayChecklist(me._group_selected, me._list_selected, me._checklists); } } }, # Reset controller if required when the page is displayed or hidden ondisplay : func() { me.RegisterWithEmesary(); # Get the list of checklists if we don't already have it. This has to # be done here rather than in the Constructor because the appropriate # Emesary interface may not have been initialized in time. if (me._checklists == nil) me.getChecklists(); }, offdisplay : func() { me.DeRegisterWithEmesary(); }, };