Skip to content

Commit

Permalink
feat(a380/mfd): status and switching page (flybywiresim#9362)
Browse files Browse the repository at this point in the history
* initial surv status page creation

* buttons for status page

* each item a separate component

* finalize status page

* update changelog
  • Loading branch information
Frenkii authored Nov 16, 2024
1 parent e34fe14 commit dccbd6a
Show file tree
Hide file tree
Showing 7 changed files with 399 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
1. [A32NX/FMGC] Implemented simulated FCU computers - @lukecologne (luke)
1. [A380X/ENGINES] Corrected ENG4 throttle variable typo - @rthom91 (Randy Thom)
1. [ND] Fixed track line not visible in GA TRK, RWY TRK and RWY modes - @ta-dzik (ta_dzik)
1. [A380X/FMS] Added SURV Status & Switching page with TCAS fault indication - @Frenkii (Moritz)

## 0.12.0

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { MfdDisplayInterface } from 'instruments/src/MFD/MFD';
import { MfdUiService } from 'instruments/src/MFD/pages/common/MfdUiService';
import { MfdFmsDataDebug } from 'instruments/src/MFD/pages/FMS/DATA/MfdFmsDataDebug';
import { MfdSurvControls } from 'instruments/src/MFD/pages/SURV/MfdSurvControls';
import { MfdSurvStatusSwitching } from 'instruments/src/MFD/pages/SURV/MfdSurvStatusSwitching';

export function pageForUrl(
url: string,
Expand Down Expand Up @@ -93,6 +94,8 @@ export function pageForUrl(
return <MfdFmsDataDebug pageTitle="DEBUG" bus={bus} mfd={mfd} fmcService={fmcService} />;
case 'surv/controls':
return <MfdSurvControls pageTitle="CONTROLS" bus={bus} mfd={mfd} fmcService={fmcService} />;
case 'surv/status-switching':
return <MfdSurvStatusSwitching pageTitle="STATUS & SWITCHING" bus={bus} mfd={mfd} fmcService={fmcService} />;
case 'atccom/connect':
return <MfdAtccomConnect pageTitle="" bus={bus} mfd={mfd} fmcService={fmcService} />;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
@import "../../../MsfsAvionicsCommon/definitions.scss";


.sys-box {
border: 1px solid $display-light-grey;
padding: 10px;
padding-top: 50px;
width: 270px;
position: relative;
}

.sys-box.active {
border: 1px solid $display-green;
}

.sys-group {
border: 1px solid $display-light-grey;
padding: 5px;
}

.sys-group.active {
border: 1px solid $display-green;
}

.sys-group.failed {
border: 1px solid $display-amber;
}

.sys-status-item.failed {
color: $display-amber;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
import { ConsumerSubject, DisplayComponent, FSComponent, Subject, Subscription, VNode } from '@microsoft/msfs-sdk';

import './MfdSurvStatusSwitching.scss';

import { MfdSurvEvents } from 'instruments/src/MsfsAvionicsCommon/providers/MfdSurvPublisher';
import { ActivePageTitleBar } from 'instruments/src/MFD/pages/common/ActivePageTitleBar';
import { AbstractMfdPageProps } from 'instruments/src/MFD/MFD';
import { Footer } from 'instruments/src/MFD/pages/common/Footer';
import { MfdSimvars } from 'instruments/src/MFD/shared/MFDSimvarPublisher';
import { SurvStatusButton } from 'instruments/src/MFD/pages/common/SurvStatusButton';
import { SurvStatusItem } from 'instruments/src/MFD/pages/common/SurvStatusItem';

interface MfdSurvStatusSwitchingProps extends AbstractMfdPageProps {}

export enum StatusItemState {
Off = 0,
On = 1,
Failed = 2,
}

export class MfdSurvStatusSwitching extends DisplayComponent<MfdSurvStatusSwitchingProps> {
// Make sure to collect all subscriptions here, otherwise page navigation doesn't work.
private subs = [] as Subscription[];

private readonly sub = this.props.bus.getSubscriber<MfdSimvars & MfdSurvEvents>();

private readonly tcas1Failed = ConsumerSubject.create(this.sub.on('tcasFail'), true);

private readonly wxr1Failed = Subject.create<boolean>(false);

private readonly turb1Failed = Subject.create<boolean>(false);

private readonly predWs1Failed = Subject.create<boolean>(false);

private readonly xpdr1Failed = Subject.create<boolean>(false);

private readonly terr1Failed = Subject.create<boolean>(false);

private readonly gpws1Failed = Subject.create<boolean>(false);

private readonly wxr2Failed = Subject.create<boolean>(false);

private readonly turb2Failed = Subject.create<boolean>(false);

private readonly predWs2Failed = Subject.create<boolean>(false);

private readonly terr2Failed = Subject.create<boolean>(false);

private readonly gpws2Failed = Subject.create<boolean>(false);

private readonly xpdr2Failed = Subject.create<boolean>(false);

private readonly tcas2Failed = Subject.create<boolean>(false);

private readonly activeSystemGroupXpdrTcas = Subject.create<number>(1);

private readonly activeSystemGroupXpdr = Subject.create<number>(1);

private readonly activeSystemGroupTcas = Subject.create<number>(1);

public onAfterRender(node: VNode): void {
super.onAfterRender(node);
}

public destroy(): void {
// Destroy all subscriptions to remove all references to this instance.
this.subs.forEach((x) => x.destroy());

super.destroy();
}

render(): VNode {
return (
<>
<ActivePageTitleBar
activePage={Subject.create('STATUS & SWITCHING')}
offset={Subject.create('')}
eoIsActive={Subject.create(false)}
tmpyIsActive={Subject.create(false)}
/>
{/* begin page content */}
<div class="mfd-page-container">
<div style="width: 100%; display: flex; flex-direction: row; justify-content: space-between; align-items: top; padding: 50px;">
{/* upper left sys box */}
<div class="sys-box">
<SurvStatusButton
label={'SYS 1'}
active={Subject.create(true)}
onClick={() => console.log('button clicked')}
/>
<div
class={{
'sys-group': true,
active: Subject.create(true),
}}
style="margin-bottom: 10px;"
>
<SurvStatusItem
label={'WXR DISPLAY'}
sys={'1'}
active={true}
failed={this.wxr1Failed}
style={'margin-bottom: 10px;'}
/>
<SurvStatusItem
label={'TURB'}
sys={'1'}
active={true}
failed={this.turb1Failed}
style={'margin-bottom: 10px;'}
/>
<SurvStatusItem label={'PRED W/S'} sys={'1'} active={true} failed={this.predWs1Failed} />
</div>
<div class={{ 'sys-group': true, active: Subject.create(true) }}>
<SurvStatusItem
label={'TERR SYS'}
sys={'1'}
active={true}
failed={this.terr1Failed}
style={'margin-bottom: 10px;'}
/>
<SurvStatusItem label={'GPWS'} sys={'1'} active={true} failed={this.gpws1Failed} />
</div>
</div>
{/* upper middle text */}
<div style="text-align: center;">
<div class="mfd-label bigger" style="margin-top: 55px;">
WXR
</div>
<div class="mfd-label bigger" style="margin-top: 90px;">
TAWS
</div>
</div>
{/* upper right sys box */}
<div class="sys-box">
<SurvStatusButton
label={'SYS 2'}
active={Subject.create(false)}
onClick={() => console.log('button clicked')}
/>
<div
class={{
'sys-group': true,
active: Subject.create(false),
}}
style="margin-bottom: 10px;"
>
<SurvStatusItem
label={'WXR DISPLAY'}
sys={'2'}
active={false}
failed={this.wxr2Failed}
style={'margin-bottom: 10px;'}
/>
<SurvStatusItem
label={'TURB'}
sys={'2'}
active={false}
failed={this.turb2Failed}
style={'margin-bottom: 10px;'}
/>
<SurvStatusItem label={'PRED W/S'} sys={'2'} active={false} failed={this.predWs2Failed} />
</div>
<div class={{ 'sys-group': true, active: Subject.create(false) }}>
<SurvStatusItem
label={'TERR SYS'}
sys={'2'}
active={false}
failed={this.terr2Failed}
style={'margin-bottom: 10px;'}
/>
<SurvStatusItem label={'GPWS'} sys={'2'} active={false} failed={this.gpws2Failed} />
</div>
</div>
</div>
{/* lower line */}
<div style="width: 100%; display: flex; flex-direction: row; justify-content: space-between; align-items: top; padding: 50px;">
{/* lower left sys box */}
<div class="sys-box">
<SurvStatusButton label={'SYS 1'} active={Subject.create(this.activeSystemGroupXpdrTcas.get() === 1)} />
<div
class={{ 'sys-group': true, active: Subject.create(this.activeSystemGroupXpdr.get() === 1) }}
style="margin-bottom: 5px;"
>
<SurvStatusItem label={'XPDR'} sys={'1'} active={true} failed={this.xpdr1Failed} />
</div>
<div class={{ 'sys-group': true, active: Subject.create(this.activeSystemGroupTcas.get() === 1) }}>
<SurvStatusItem label={'TCAS'} sys={'1'} active={true} failed={this.tcas1Failed} />
</div>
</div>
{/* lower middle text */}
<div style="text-align: center;">
<div class="mfd-label bigger" style="margin-top: 55px;">
XPDR
</div>
<div class="mfd-label bigger" style="margin-top: 20px;">
TCAS
</div>
</div>
{/* lower right sys box */}
<div class="sys-box">
<SurvStatusButton
label={'SYS 2'}
active={Subject.create(false)}
onClick={() => console.log('button clicked')}
/>
<div
class={{ 'sys-group': true, active: Subject.create(this.activeSystemGroupXpdr.get() === 2) }}
style="margin-bottom: 5px;"
>
<SurvStatusItem label={'XPDR'} sys={'2'} active={false} failed={this.xpdr2Failed} />
</div>
<div class={{ 'sys-group': true, active: Subject.create(this.activeSystemGroupTcas.get() === 2) }}>
<SurvStatusItem label={'TCAS'} sys={'2'} active={false} failed={this.tcas2Failed} />
</div>
</div>
</div>
</div>
{/* end page content */}
<Footer bus={this.props.bus} mfd={this.props.mfd} fmcService={this.props.fmcService} />
</>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { ComponentProps, DisplayComponent, FSComponent, Subscribable, Subscription, VNode } from '@microsoft/msfs-sdk';
import './style.scss';

export interface SurvStatusButtonProps extends ComponentProps {
label: string;
active: Subscribable<boolean>;
onChanged?(val: boolean): void;
onClick?: () => void;
}

/*
* Button for MFD pages. If menuItems is set, a dropdown menu will be displayed when button is clicked
*/
export class SurvStatusButton extends DisplayComponent<SurvStatusButtonProps> {
// Make sure to collect all subscriptions here, otherwise page navigation doesn't work.
private subs = [] as Subscription[];

private buttonRef = FSComponent.createRef<HTMLSpanElement>();

private clickHandler(): void {
console.log(this.props.label + 'button clicked');
}

public onAfterRender(node: VNode): void {
super.onAfterRender(node);

this.buttonRef.instance.addEventListener('click', () => this.clickHandler());
}

public destroy(): void {
// Destroy all subscriptions to remove all references to this instance.
this.subs.forEach((x) => x.destroy());

super.destroy();
}

public render(): VNode {
return (
<div ref={this.buttonRef} class="mfd-surv-status-button">
<div style="padding-left: 7px; padding-right: 7px; height: 50%; background-color: black; display: flex; flex-direction: column; justify-content: space-evenly;">
<div class={{ 'mfd-surv-status-indicator': true, active: this.props.active }}></div>
<div class={{ 'mfd-surv-status-indicator': true, active: this.props.active }}></div>
<div class={{ 'mfd-surv-status-indicator': true, active: this.props.active }}></div>
</div>
<p class="mfd-surv-status-button-label">{this.props.label}</p>
</div>
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { ComponentProps, DisplayComponent, FSComponent, Subscribable, Subscription, VNode } from '@microsoft/msfs-sdk';
import './style.scss';

export interface SurvStatusItemProps extends ComponentProps {
label: string;
active: boolean;
failed: Subscribable<boolean>;
sys: string;
style?: string;
onChanged?(val: boolean): void;
}

/*
* Button for MFD pages. If menuItems is set, a dropdown menu will be displayed when button is clicked
*/
export class SurvStatusItem extends DisplayComponent<SurvStatusItemProps> {
// Make sure to collect all subscriptions here, otherwise page navigation doesn't work.
private subs = [] as Subscription[];

public onAfterRender(node: VNode): void {
super.onAfterRender(node);
}

public destroy(): void {
// Destroy all subscriptions to remove all references to this instance.
this.subs.forEach((x) => x.destroy());

super.destroy();
}

public render(): VNode {
return (
<div
style={this.props.style}
class={{
'mfd-surv-status-item': true,
active: this.props.active,
failed: this.props.failed,
}}
>
{this.props.label} {this.props.active ? this.props.sys : 'OFF'}
</div>
);
}
}
Loading

0 comments on commit dccbd6a

Please sign in to comment.