Skip to main content

G3000 Display Panes

Introduction

Display panes are window-like elements found on the G3000 MFD and PFDs that present various graphical and textual information, such as moving maps and systems synoptics, in a modular fashion. Each pane can display multiple views, though only one view can be visible at a time. Panes can also be hidden and resized. The user controls display panes through the touchscreen controllers (GTCs).

Pane Basics

Each MFD and PFD contains two display panes, for a total of six when the full set of two PFDs and one MFD is included in an installation. One display pane on each PFD is always reserved for the primary instruments display; this pane is always visible and cannot display any other view. The other display panes (up to four total) can be fully controlled by the user. Each display pane is referenced by a numeric index. The indexes are defined by the DisplayPaneIndex enum.

Panes can be either hidden, full-size or half-size. The controllable PFD pane is hidden when the PFD is in Full mode and half-size when the PFD is in Split mode (it is never full-size). Each of the two MFD panes can be in any of these three states depending whether the MFD is in Full mode or Half mode.

Pane Dimensions

This table presents the dimensions of the various display panes, which may be helpful when laying out pane views:

PaneSizeWidth (px)Height (px)
PFD (instrument)Full1280800
PFD (instrument)Half768800
PFD (controllable)Half508778
MFDFull995748
MFDHalf495748

These dimensions only include the usable space available to views in the pane, and exclude any pane headers or borders.

Pane Views

Each display pane displays one of many possible views at a time. Display pane views contain the bulk of the visual content of a pane. All display pane views are implemented as FS components that extend the abstract class DisplayPaneView.

Views should define a title that will appear in the header of its parent pane. View titles can be defined as a simple string or a VNode. No matter how a title is defined, its rendered form must fit within a single line in the pane header.

Here is an example of a simple pane view that has the title CURRENT TIME but doesn't do much else:

import { DisplayPaneView } from '@microsoft/msfs-wtg3000-common';

export class TimePaneView extends DisplayPaneView {
private readonly time = Subject.create('');

public onAfterRender(): void {
// Sets the title of the view.
this._title.set('CURRENT TIME');
}

public render(): VNode {
return (
<div>{this.time}</div>
);
}
}

Each view must be registered with an appropriate display pane view factory before it can be displayed in a pane. Views are registered under specific keys. These keys are then used to reference views in an abstract manner. If multiple views are registered with the same factory under the same key, the most recent view to be registered will replace the older views.

info

The DisplayPaneViewKeys enum contains all display pane view keys defined and used by the base G3000.

Views can be created as half-size-only views by setting their halfSizeOnly prop to true. These views can only be displayed in half-size panes. Attempting to display a half-size-only view in a full-size MFD pane will force the MFD into Half mode. If a half-size-only view is active in a half-size MFD pane, the user will not be able to switch the MFD to Full mode with that pane as the full-size pane.

Pane View Lifecycle Callbacks

Each display pane view has access to four lifecycle callback methods defined in the DisplayPaneView abstract class. By default, these methods do nothing, so a view must override them in order to provide its own functionality.

onResume()

This method is called when a view transitions from not visible to visible. This could be because it became the active view or because its parent pane exited the hidden state.

The current size of the view's parent pane (full or half) and its dimensions are passed to the method as parameters.

All views are created as initially not visible. Therefore, onResume() is guaranteed to be called before the first time the view becomes visible to the user.

onUpdate()

This method is called regularly whenever the view is visible (i.e. when it is active and its parent pane is not hidden). This makes it a good place from which to run updates that only need to occur when the user can see the changes. The first call to onUpdate() after a view becomes visible is guaranteed to come after the call to onResume().

The frequency with which onUpdate() is called is tied to the Javascript instrument's refresh rate (itself a function of the sim's framerate and the cockpit refresh rate setting). Addtionally, onUpdate() is throttled when a display pane is half-size such that the two half-size panes on the same instrument will alternate updates with each instrument refresh cycle (pane A updates on cycle 1, pane B on cycle 2, pane A on cycle 3, and so on).

onResize()

This method is called when the view's parent pane is resized while the view is visible. The new size of the view's parent pane (full or half) and its dimensions are passed to the method as parameters.

caution

onResize() is not called when a view is not visible. Therefore, it is always recommended to also use the size information passed to the onResume() method to update the view as necessary when it becomes visible.

onPause()

This method is called when a view transitions from visible to not visible.

Example

Building on our TimePaneView example from above, we can use lifecycle methods to have the view display the current operating system time and dynamically adjust its font to be larger when the view's parent pane is full-size (unchanged code from the prior version has been elided):

import { DisplayPaneSizeMode, DisplayPaneView } from '@microsoft/msfs-wtg3000-common';

export class TimePaneView extends DisplayPaneView {
private readonly style = ObjectSubject.create({
'font-size': '16px'
});

// ...

public onResume(size: DisplayPaneSizeMode): void {
this.updateFontSize(size);
}

public onResize(size: DisplayPaneSizeMode): void {
this.updateFontSize(size);
}

private updateFontSize(size: DisplayPaneSizeMode): void {
// Updates font size to take advantage of wider panes in full mode.
if (size === DisplayPaneSizeMode.Full) {
this.style.set('font-size', '24px');
} else {
this.style.set('font-size', '16px');
}
}

public onUpdate(time: number): void {
// Updates the displayed time string.
this.time.set(new Date(time).toUTCString())
}

public render(): VNode {
return (
<div style={this.style}>{this.time}</div>
);
}
}

Designated Pane Views

Each display pane has a set of what are known as designated views. These views function as sort of the "default" active views for a pane. Of these designated views, one is the primary designated view and the others are context-specific designated views.

The primary designated view for a pane is the view that is chosen to replace a closed view as the pane's active view when no other specific replacement view has been selected.

Context-specific designated views function similarly to the primary designated view, except (as their name implies) only under specific contexts. For example, the designated weather view applies only when the user has selected the Weather button on the GTC MFD Home page. The primary designated view should always be equal to a context-specific designated view while its context is active. While its context is not active, a context-specific designated view typically retains its most recent value until its context becomes active again.

Designated pane views are typically selected by the user using the GTCs. Designated pane view logic is not handled automatically and must be manually implemented by any GTC view that wishes to work with designated views. The GtcDesignatedPaneButton component is provided to facilitate creation of buttons that control designated pane views.

Display Pane User Settings

There are a number of user settings related to display panes. These can be accessed to retrieve information about display pane state, or in some instances, to control certain aspects of panes.

Display pane user settings are defined on a per-pane basis. The settings for all panes are included in the DisplayPaneAllUserSettingTypes type. All setting names are suffixed with the index of the pane to which they apply. The setting names without the index suffixes are included in the DisplayPaneSettings type. The static methods in the DisplayPanesUserSettings utility class can be used to retrieve managers for either all pane settings or aliased settings (without the index suffix) for a specific pane.

Only a subset of display pane user settings are meant to be modified by code outside of the core display pane system. The rest are to be treated as read-only. The following table lists which ones are which.

Setting Name (Aliased)Modifiable
displayPaneVisibleNo
displayPaneViewYes
displayPaneDesignatedViewYes
displayPaneDesignatedWeatherViewYes
displayPaneControllerNo
displayPaneHalfSizeOnlyNo
displayPaneMapPointerActiveYes

Controlling Panes

Display panes can be controlled via a combination of user settings (see above) and commands sent over the event bus. Display pane event bus commands are defined by the DisplayPaneControlEvents type. When publishing event bus commands, the sync option must be set to true, and the cached option must be set to false.

Controlling the visibility and size of panes is accomplished by sending the toggle_pfd_split and toggle_mfd_split events. These events will toggle the PFD between Full and Split mode, and the MFD between Full and Half mode, respectively. You will generally not need to use these events since the logic is already handled by the base G3000 package.

Controlling the active view displayed by a pane is accomplished by writing the key of the view to the appropriate pane-specific displayPaneView user setting. Likewise, the displayPaneDesignatedView and displayPaneDesignatedWeatherView settings control the designated views for a pane.

Controlling which GTC controls which pane is accomplished by sending the gtc_1_display_pane_select, gtc_2_display_pane_select, change_display_pane_select_left, and change_display_pane_select_right events. You will generally not need to use these events since the logic is already handled by the base G3000 package.

Controlling Pane Views

Commands can be sent to display pane views by publishing the display_pane_view_event topic to the event bus. The topic should always be published with the sync option set to true and cached option set to false.

The display_pane_view_event topic requires a data packet in the form of an object that extends the DisplayPaneViewEvent interface. The data packet defines the index of the pane that is the target of the command. Only the active view of the specified pane will receive the command. The data packet also defines an event type (an arbitrary string) and additional data specific to that event type.

Display pane views can respond to commands via the onEvent() callback method, which accepts the received command event as its only parameter. By default, the event passed into onEvent() is typed such that it can have any arbitrary string as its event type and event data of type any. You may optionally elect to narrow the event type accepted by onEvent() using the second optional type parameter on DisplayPaneView.

For an example of display pane view events in action, we can expand TimePaneView from above to have it respond to commands to format the time as UTC or local time (unchanged code from the prior version has been elided):

import { DisplayPaneView, DisplayPaneViewEvent, DisplayPaneViewProps } from '@microsoft/msfs-wtg3000-common';

export interface TimePaneViewEventTypes {
time_pane_format_set: 'utc' | 'local';
}

export class TimePaneView extends DisplayPaneView<
DisplayPaneViewProps,
DisplayPaneViewEvent<TimePaneViewEventTypes>
> {

private format: 'utc' | 'local' = 'utc';

// ...

public onAfterRender(): void {
// Sets the title of the view.
this._title.set('CURRENT UTC TIME');
}

public onUpdate(time: number): void {
// Updates the displayed time string.

const date = new Date(time);
const text = this.format === 'utc'
? date.toUTCString()
: date.toString();

this.time.set(text);
}

public onEvent(e: DisplayPaneViewEvent<TimePaneViewEventTypes>): void {
if (e.eventType === 'time_pane_format_set') {
this.format = e.eventData;
this._title.set(`CURRENT ${this.format === 'utc' ? 'UTC' : 'LOCAL'} TIME`);
}
}
}

Full Example of a Pane View

Here is the full example pane view that was incrementally built up over the previous sections.

import { FSComponent, ObjectSubject, Subject, VNode } from '@microsoft/msfs-sdk';
import {
DisplayPaneSizeMode, DisplayPaneView, DisplayPaneViewEvent, DisplayPaneViewProps
} from '@microsoft/msfs-wtg3000-common';

export interface TimePaneViewEventTypes {
time_pane_format_set: 'utc' | 'local';
}

export class TimePaneView extends DisplayPaneView<
DisplayPaneViewProps,
DisplayPaneViewEvent<TimePaneViewEventTypes>
> {

private format: 'utc' | 'local' = 'utc';
private readonly time = Subject.create('');

private readonly style = ObjectSubject.create({
'font-size': '16px'
});

public onAfterRender(): void {
// Sets the title of the view.
this._title.set('CURRENT UTC TIME');
}

public onResume(size: DisplayPaneSizeMode): void {
this.updateFontSize(size);
}

public onResize(size: DisplayPaneSizeMode): void {
this.updateFontSize(size);
}

private updateFontSize(size: DisplayPaneSizeMode): void {
// Updates font size to take advantage of wider panes in full mode.
if (size === DisplayPaneSizeMode.Full) {
this.style.set('font-size', '24px');
} else {
this.style.set('font-size', '16px');
}
}

public onUpdate(time: number): void {
// Updates the displayed time string.

const date = new Date(time);
const text = this.format === 'utc'
? date.toUTCString()
: date.toString();

this.time.set(text);
}

public onEvent(e: DisplayPaneViewEvent<TimePaneViewEventTypes>): void {
if (e.eventType === 'time_pane_format_set') {
this.format = e.eventData;
this._title.set(`CURRENT ${this.format === 'utc' ? 'UTC' : 'LOCAL'} TIME`);
}
}

public render(): VNode {
return (
<div style={this.style}>{this.time}</div>
);
}
}

TimePaneView displays the operating system time. It dynamically adjusts the size of its font to be larger when its parent pane is full-size. It will switch between formatting the time as UTC time and local time based on display pane view events sent to it by outside code. Finally, its title is set to either "CURRENT UTC TIME" or "CURRENT LOCAL TIME", depending on how it is formatting the displayed time.