mirror of
https://github.com/nasa/openmct.git
synced 2025-06-15 21:58:13 +00:00
921 lines
27 KiB
JavaScript
921 lines
27 KiB
JavaScript
/*****************************************************************************
|
|
* Open MCT, Copyright (c) 2014-2024, United States Government
|
|
* as represented by the Administrator of the National Aeronautics and Space
|
|
* Administration. All rights reserved.
|
|
*
|
|
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
* http://www.apache.org/licenses/LICENSE-2.0.
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
* License for the specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
* Open MCT includes source code licensed under additional open source
|
|
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
|
* this source code distribution or the Licensing information page available
|
|
* at runtime from the About dialog for additional information.
|
|
*****************************************************************************/
|
|
|
|
import _ from 'lodash';
|
|
|
|
const CONTEXT_ACTION = 'contextAction';
|
|
const CONTEXT_ACTIONS = Object.freeze({
|
|
ADD_ELEMENT: 'addElement',
|
|
REMOVE_ITEM: 'removeItem',
|
|
DUPLICATE_ITEM: 'duplicateItem',
|
|
ORDER_ITEM: 'orderItem',
|
|
SWITCH_VIEW_TYPE: 'switchViewType',
|
|
MERGE_MULTIPLE_TELEMETRY_VIEWS: 'mergeMultipleTelemetryViews',
|
|
MERGE_MULTIPLE_OVERLAY_PLOTS: 'mergeMultipleOverlayPlots',
|
|
TOGGLE_GRID: 'toggleGrid'
|
|
});
|
|
|
|
const DIALOG_FORM = {
|
|
text: {
|
|
title: 'Text Element Properties',
|
|
sections: [
|
|
{
|
|
rows: [
|
|
{
|
|
key: 'text',
|
|
control: 'textfield',
|
|
name: 'Text',
|
|
required: true,
|
|
cssClass: 'l-input-lg'
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
image: {
|
|
title: 'Image Properties',
|
|
sections: [
|
|
{
|
|
rows: [
|
|
{
|
|
key: 'url',
|
|
control: 'textfield',
|
|
name: 'Image URL',
|
|
cssClass: 'l-input-lg',
|
|
required: true
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
};
|
|
const VIEW_TYPES = {
|
|
'telemetry-view': {
|
|
value: 'telemetry-view',
|
|
name: 'Alphanumeric',
|
|
class: 'icon-alphanumeric'
|
|
},
|
|
'telemetry.plot.overlay': {
|
|
value: 'telemetry.plot.overlay',
|
|
name: 'Overlay Plot',
|
|
class: 'icon-plot-overlay'
|
|
},
|
|
'telemetry.plot.stacked': {
|
|
value: 'telemetry.plot.stacked',
|
|
name: 'Stacked Plot',
|
|
class: 'icon-plot-stacked'
|
|
},
|
|
table: {
|
|
value: 'table',
|
|
name: 'Table',
|
|
class: 'icon-tabular-scrolling'
|
|
}
|
|
};
|
|
const APPLICABLE_VIEWS = {
|
|
'telemetry-view': [
|
|
VIEW_TYPES['telemetry.plot.overlay'],
|
|
VIEW_TYPES['telemetry.plot.stacked'],
|
|
VIEW_TYPES.table
|
|
],
|
|
'telemetry.plot.overlay': [
|
|
VIEW_TYPES['telemetry.plot.stacked'],
|
|
VIEW_TYPES.table,
|
|
VIEW_TYPES['telemetry-view']
|
|
],
|
|
'telemetry.plot.stacked': [
|
|
VIEW_TYPES['telemetry.plot.overlay'],
|
|
VIEW_TYPES.table,
|
|
VIEW_TYPES['telemetry-view']
|
|
],
|
|
table: [
|
|
VIEW_TYPES['telemetry.plot.overlay'],
|
|
VIEW_TYPES['telemetry.plot.stacked'],
|
|
VIEW_TYPES['telemetry-view']
|
|
],
|
|
'telemetry-view-multi': [
|
|
VIEW_TYPES['telemetry.plot.overlay'],
|
|
VIEW_TYPES['telemetry.plot.stacked'],
|
|
VIEW_TYPES.table
|
|
],
|
|
'telemetry.plot.overlay-multi': [VIEW_TYPES['telemetry.plot.stacked']]
|
|
};
|
|
|
|
export default class DisplayLayoutToolbar {
|
|
#openmct;
|
|
|
|
constructor(openmct) {
|
|
this.#openmct = openmct;
|
|
this.name = 'Display Layout Toolbar';
|
|
this.key = 'layout';
|
|
this.description = 'A toolbar for objects inside a display layout.';
|
|
}
|
|
|
|
forSelection(selection) {
|
|
if (!selection || selection.length === 0) {
|
|
return false;
|
|
}
|
|
|
|
let selectionPath = selection[0];
|
|
let selectedObject = selectionPath[0];
|
|
let selectedParent = selectionPath[1];
|
|
|
|
// Apply the layout toolbar if the selected object is inside a layout, or the main layout is selected.
|
|
return (
|
|
(selectedParent &&
|
|
selectedParent.context.item &&
|
|
selectedParent.context.item.type === 'layout') ||
|
|
(selectedObject.context.item && selectedObject.context.item.type === 'layout')
|
|
);
|
|
}
|
|
|
|
#getPath(selectionPath) {
|
|
return `configuration.items[${selectionPath[0].context.index}]`;
|
|
}
|
|
|
|
#getAllOfType(selection, specificType) {
|
|
return selection.filter((selectionPath) => {
|
|
let type = selectionPath[0].context.layoutItem.type;
|
|
|
|
return type === specificType;
|
|
});
|
|
}
|
|
|
|
#getAllTypes(selection) {
|
|
return selection.filter((selectionPath) => {
|
|
let type = selectionPath[0].context.layoutItem.type;
|
|
|
|
return (
|
|
type === 'text-view' ||
|
|
type === 'telemetry-view' ||
|
|
type === 'box-view' ||
|
|
type === 'ellipse-view' ||
|
|
type === 'image-view' ||
|
|
type === 'line-view' ||
|
|
type === 'subobject-view'
|
|
);
|
|
});
|
|
}
|
|
|
|
#getAddButton(selection, selectionPath) {
|
|
if (selection.length === 1) {
|
|
selectionPath = selectionPath || selection[0];
|
|
const domainObject = selectionPath[0].context.item;
|
|
const keyString = this.#openmct.objects.makeKeyString(domainObject.identifier);
|
|
|
|
return {
|
|
control: 'menu',
|
|
domainObject,
|
|
method: (option) => {
|
|
let name = option.name.toLowerCase();
|
|
let form = DIALOG_FORM[name];
|
|
if (form) {
|
|
this.#showForm(form, name, selection);
|
|
} else {
|
|
this.#openmct.objectViews.emit(
|
|
`${CONTEXT_ACTION}:${keyString}`,
|
|
CONTEXT_ACTIONS.ADD_ELEMENT,
|
|
name,
|
|
selection
|
|
);
|
|
}
|
|
},
|
|
key: 'add',
|
|
icon: 'icon-plus',
|
|
label: 'Add Drawing Object',
|
|
options: [
|
|
{
|
|
name: 'Box',
|
|
class: 'icon-box-round-corners'
|
|
},
|
|
{
|
|
name: 'Ellipse',
|
|
class: 'icon-circle'
|
|
},
|
|
{
|
|
name: 'Line',
|
|
class: 'icon-line-horz'
|
|
},
|
|
{
|
|
name: 'Text',
|
|
class: 'icon-font'
|
|
},
|
|
{
|
|
name: 'Image',
|
|
class: 'icon-image'
|
|
}
|
|
]
|
|
};
|
|
}
|
|
}
|
|
|
|
#getToggleFrameButton(selectedParent, selection) {
|
|
return {
|
|
control: 'toggle-button',
|
|
domainObject: selectedParent,
|
|
applicableSelectedItems: selection.filter(
|
|
(selectionPath) => selectionPath[0].context.layoutItem.type === 'subobject-view'
|
|
),
|
|
property: (selectionPath) => {
|
|
return this.#getPath(selectionPath) + '.hasFrame';
|
|
},
|
|
options: [
|
|
{
|
|
value: false,
|
|
icon: 'icon-frame-hide',
|
|
title: 'Frame visible',
|
|
label: 'Hide frame'
|
|
},
|
|
{
|
|
value: true,
|
|
icon: 'icon-frame-show',
|
|
title: 'Frame hidden',
|
|
label: 'Show frame'
|
|
}
|
|
]
|
|
};
|
|
}
|
|
|
|
#getRemoveButton(selectedParent, selectionPath, selection) {
|
|
const domainObject = selectedParent;
|
|
const keyString = this.#openmct.objects.makeKeyString(domainObject.identifier);
|
|
return {
|
|
control: 'button',
|
|
domainObject,
|
|
icon: 'icon-trash',
|
|
title: 'Delete the selected object',
|
|
method: () => {
|
|
let prompt = this.#openmct.overlays.dialog({
|
|
iconClass: 'alert',
|
|
message: `Warning! This action will remove this item from the Display Layout. Do you want to continue?`,
|
|
buttons: [
|
|
{
|
|
label: 'OK',
|
|
emphasis: 'true',
|
|
callback: () => {
|
|
this.#openmct.objectViews.emit(
|
|
`${CONTEXT_ACTION}:${keyString}`,
|
|
CONTEXT_ACTIONS.REMOVE_ITEM,
|
|
this.#getAllTypes(selection),
|
|
selection
|
|
);
|
|
prompt.dismiss();
|
|
}
|
|
},
|
|
{
|
|
label: 'Cancel',
|
|
callback: function () {
|
|
prompt.dismiss();
|
|
}
|
|
}
|
|
]
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
#getStackOrder(selectedParent, selectionPath, selectedObjects) {
|
|
const domainObject = selectedParent;
|
|
const keyString = this.#openmct.objects.makeKeyString(domainObject.identifier);
|
|
return {
|
|
control: 'menu',
|
|
domainObject,
|
|
icon: 'icon-layers',
|
|
title: 'Move the selected object above or below other objects',
|
|
options: [
|
|
{
|
|
name: 'Move to Top',
|
|
value: 'top',
|
|
class: 'icon-arrow-double-up'
|
|
},
|
|
{
|
|
name: 'Move Up',
|
|
value: 'up',
|
|
class: 'icon-arrow-up'
|
|
},
|
|
{
|
|
name: 'Move Down',
|
|
value: 'down',
|
|
class: 'icon-arrow-down'
|
|
},
|
|
{
|
|
name: 'Move to Bottom',
|
|
value: 'bottom',
|
|
class: 'icon-arrow-double-down'
|
|
}
|
|
],
|
|
method: (option) => {
|
|
this.#openmct.objectViews.emit(
|
|
`${CONTEXT_ACTION}:${keyString}`,
|
|
CONTEXT_ACTIONS.ORDER_ITEM,
|
|
option.value,
|
|
this.#getAllTypes(selectedObjects)
|
|
);
|
|
}
|
|
};
|
|
}
|
|
|
|
#getXInput(selectedParent, selection) {
|
|
if (selection.length === 1) {
|
|
return {
|
|
control: 'input',
|
|
type: 'number',
|
|
domainObject: selectedParent,
|
|
applicableSelectedItems: this.#getAllTypes(selection),
|
|
property: (selectionPath) => {
|
|
return this.#getPath(selectionPath) + '.x';
|
|
},
|
|
label: 'X:',
|
|
title: 'X position'
|
|
};
|
|
}
|
|
}
|
|
|
|
#getYInput(selectedParent, selection) {
|
|
if (selection.length === 1) {
|
|
return {
|
|
control: 'input',
|
|
type: 'number',
|
|
domainObject: selectedParent,
|
|
applicableSelectedItems: this.#getAllTypes(selection),
|
|
property: (selectionPath) => {
|
|
return this.#getPath(selectionPath) + '.y';
|
|
},
|
|
label: 'Y:',
|
|
title: 'Y position'
|
|
};
|
|
}
|
|
}
|
|
|
|
#getWidthInput(selectedParent, selection) {
|
|
if (selection.length === 1) {
|
|
return {
|
|
control: 'input',
|
|
type: 'number',
|
|
domainObject: selectedParent,
|
|
applicableSelectedItems: this.#getAllTypes(selection),
|
|
property: (selectionPath) => {
|
|
return this.#getPath(selectionPath) + '.width';
|
|
},
|
|
label: 'W:',
|
|
title: 'Resize object width'
|
|
};
|
|
}
|
|
}
|
|
|
|
#getHeightInput(selectedParent, selection) {
|
|
if (selection.length === 1) {
|
|
return {
|
|
control: 'input',
|
|
type: 'number',
|
|
domainObject: selectedParent,
|
|
applicableSelectedItems: this.#getAllTypes(selection),
|
|
property: (selectionPath) => {
|
|
return this.#getPath(selectionPath) + '.height';
|
|
},
|
|
label: 'H:',
|
|
title: 'Resize object height'
|
|
};
|
|
}
|
|
}
|
|
|
|
#getX2Input(selectedParent, selection) {
|
|
if (selection.length === 1) {
|
|
return {
|
|
control: 'input',
|
|
type: 'number',
|
|
domainObject: selectedParent,
|
|
applicableSelectedItems: selection.filter((selectionPath) => {
|
|
return selectionPath[0].context.layoutItem.type === 'line-view';
|
|
}),
|
|
property: (selectionPath) => {
|
|
return this.#getPath(selectionPath) + '.x2';
|
|
},
|
|
label: 'X2:',
|
|
title: 'X2 position'
|
|
};
|
|
}
|
|
}
|
|
|
|
#getY2Input(selectedParent, selection) {
|
|
if (selection.length === 1) {
|
|
return {
|
|
control: 'input',
|
|
type: 'number',
|
|
domainObject: selectedParent,
|
|
applicableSelectedItems: selection.filter((selectionPath) => {
|
|
return selectionPath[0].context.layoutItem.type === 'line-view';
|
|
}),
|
|
property: (selectionPath) => {
|
|
return this.#getPath(selectionPath) + '.y2';
|
|
},
|
|
label: 'Y2:',
|
|
title: 'Y2 position'
|
|
};
|
|
}
|
|
}
|
|
|
|
#getTextButton(selectedParent, selection) {
|
|
return {
|
|
control: 'button',
|
|
domainObject: selectedParent,
|
|
applicableSelectedItems: selection.filter((selectionPath) => {
|
|
return selectionPath[0].context.layoutItem.type === 'text-view';
|
|
}),
|
|
property: (selectionPath) => {
|
|
return this.#getPath(selectionPath);
|
|
},
|
|
icon: 'icon-pencil',
|
|
title: 'Edit text properties',
|
|
label: 'Edit text',
|
|
dialog: DIALOG_FORM.text
|
|
};
|
|
}
|
|
|
|
#getTelemetryValueMenu(selectionPath, selection) {
|
|
if (selection.length === 1) {
|
|
return {
|
|
control: 'select-menu',
|
|
domainObject: selectionPath[1].context.item,
|
|
applicableSelectedItems: selection.filter((path) => {
|
|
return path[0].context.layoutItem.type === 'telemetry-view';
|
|
}),
|
|
property: (path) => {
|
|
return this.#getPath(path) + '.value';
|
|
},
|
|
title: 'Set value',
|
|
options: this.#openmct.telemetry
|
|
.getMetadata(selectionPath[0].context.item)
|
|
.values()
|
|
.map((value) => {
|
|
return {
|
|
name: value.name,
|
|
value: value.key
|
|
};
|
|
})
|
|
};
|
|
}
|
|
}
|
|
|
|
#getDisplayModeMenu(selectedParent, selection) {
|
|
if (selection.length === 1) {
|
|
return {
|
|
control: 'select-menu',
|
|
domainObject: selectedParent,
|
|
applicableSelectedItems: selection.filter((selectionPath) => {
|
|
return selectionPath[0].context.layoutItem.type === 'telemetry-view';
|
|
}),
|
|
property: (selectionPath) => {
|
|
return this.#getPath(selectionPath) + '.displayMode';
|
|
},
|
|
title: 'Set display mode',
|
|
options: [
|
|
{
|
|
name: 'Label + Value',
|
|
value: 'all'
|
|
},
|
|
{
|
|
name: 'Label only',
|
|
value: 'label'
|
|
},
|
|
{
|
|
name: 'Value only',
|
|
value: 'value'
|
|
}
|
|
]
|
|
};
|
|
}
|
|
}
|
|
|
|
#getDuplicateButton(selectedParent, selectionPath, selection) {
|
|
const domainObject = selectedParent;
|
|
const keyString = this.#openmct.objects.makeKeyString(domainObject.identifier);
|
|
return {
|
|
control: 'button',
|
|
domainObject,
|
|
icon: 'icon-duplicate',
|
|
title: 'Duplicate the selected object',
|
|
method: () => {
|
|
this.#openmct.objectViews.emit(
|
|
`${CONTEXT_ACTION}:${keyString}`,
|
|
CONTEXT_ACTIONS.DUPLICATE_ITEM,
|
|
selection
|
|
);
|
|
}
|
|
};
|
|
}
|
|
|
|
#getPropertyFromPath(object, path) {
|
|
let splitPath = path.split('.');
|
|
let property = Object.assign({}, object);
|
|
|
|
while (splitPath.length && property) {
|
|
property = property[splitPath.shift()];
|
|
}
|
|
|
|
return property;
|
|
}
|
|
|
|
#areAllViews(type, path, selection) {
|
|
let allTelemetry = true;
|
|
|
|
selection.forEach((selectedItem) => {
|
|
let selectedItemContext = selectedItem[0].context;
|
|
|
|
if (this.#getPropertyFromPath(selectedItemContext, path) !== type) {
|
|
allTelemetry = false;
|
|
}
|
|
});
|
|
|
|
return allTelemetry;
|
|
}
|
|
|
|
#getToggleUnitsButton(selectedParent, selection) {
|
|
let applicableItems = this.#getAllOfType(selection, 'telemetry-view');
|
|
applicableItems = this.#unitsOnly(applicableItems);
|
|
if (!applicableItems.length) {
|
|
return;
|
|
}
|
|
|
|
return {
|
|
control: 'toggle-button',
|
|
domainObject: selectedParent,
|
|
applicableSelectedItems: applicableItems,
|
|
property: (selectionPath) => {
|
|
return this.#getPath(selectionPath) + '.showUnits';
|
|
},
|
|
options: [
|
|
{
|
|
value: true,
|
|
icon: 'icon-eye-open',
|
|
title: 'Show units',
|
|
label: 'Show units'
|
|
},
|
|
{
|
|
value: false,
|
|
icon: 'icon-eye-disabled',
|
|
title: 'Hide units',
|
|
label: 'Hide units'
|
|
}
|
|
]
|
|
};
|
|
}
|
|
|
|
#unitsOnly(items) {
|
|
let results = items.filter((item) => {
|
|
let currentItem = item[0];
|
|
let metadata = this.#openmct.telemetry.getMetadata(currentItem.context.item);
|
|
if (!metadata) {
|
|
return false;
|
|
}
|
|
|
|
let hasUnits = metadata.valueMetadatas.filter((metadatum) => metadatum.unit).length;
|
|
|
|
return hasUnits > 0;
|
|
});
|
|
|
|
return results;
|
|
}
|
|
|
|
#getViewSwitcherMenu(selectedParent, selectionPath, selection) {
|
|
if (selection.length === 1) {
|
|
let selectedItemContext = selectionPath[0].context;
|
|
let selectedItemType = selectedItemContext.item.type;
|
|
|
|
if (selectedItemContext.layoutItem.type === 'telemetry-view') {
|
|
selectedItemType = 'telemetry-view';
|
|
}
|
|
|
|
let viewOptions = APPLICABLE_VIEWS[selectedItemType];
|
|
|
|
if (viewOptions) {
|
|
const domainObject = selectedParent;
|
|
const keyString = this.#openmct.objects.makeKeyString(domainObject.identifier);
|
|
return {
|
|
control: 'menu',
|
|
domainObject,
|
|
icon: 'icon-object',
|
|
title: 'Switch the way this telemetry is displayed',
|
|
label: 'View type',
|
|
options: viewOptions,
|
|
method: (option) => {
|
|
this.#openmct.objectViews.emit(
|
|
`${CONTEXT_ACTION}:${keyString}`,
|
|
CONTEXT_ACTIONS.SWITCH_VIEW_TYPE,
|
|
selectedItemContext,
|
|
option.value,
|
|
selection
|
|
);
|
|
}
|
|
};
|
|
}
|
|
} else if (selection.length > 1) {
|
|
const domainObject = selectedParent;
|
|
const keyString = this.#openmct.objects.makeKeyString(domainObject.identifier);
|
|
if (this.#areAllViews('telemetry-view', 'layoutItem.type', selection)) {
|
|
return {
|
|
control: 'menu',
|
|
domainObject,
|
|
icon: 'icon-object',
|
|
title: 'Merge into a telemetry table or plot',
|
|
label: 'View type',
|
|
options: APPLICABLE_VIEWS['telemetry-view-multi'],
|
|
method: (option) => {
|
|
this.#openmct.objectViews.emit(
|
|
`${CONTEXT_ACTION}:${keyString}`,
|
|
CONTEXT_ACTIONS.MERGE_MULTIPLE_TELEMETRY_VIEWS,
|
|
selection,
|
|
option.value
|
|
);
|
|
}
|
|
};
|
|
} else if (this.#areAllViews('telemetry.plot.overlay', 'item.type', selection)) {
|
|
return {
|
|
control: 'menu',
|
|
domainObject,
|
|
icon: 'icon-object',
|
|
title: 'Merge into a stacked plot',
|
|
options: APPLICABLE_VIEWS['telemetry.plot.overlay-multi'],
|
|
method: (option) => {
|
|
this.#openmct.objectViews.emit(
|
|
`${CONTEXT_ACTION}:${keyString}`,
|
|
CONTEXT_ACTIONS.MERGE_MULTIPLE_OVERLAY_PLOTS,
|
|
selection,
|
|
option.value
|
|
);
|
|
}
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
#getToggleGridButton(selection, selectionPath) {
|
|
const ICON_GRID_SHOW = 'icon-grid-on';
|
|
const ICON_GRID_HIDE = 'icon-grid-off';
|
|
|
|
let displayLayoutContext;
|
|
|
|
if (selection.length === 1 && selectionPath === undefined) {
|
|
displayLayoutContext = selection[0][0].context;
|
|
} else {
|
|
displayLayoutContext = selectionPath[1].context;
|
|
}
|
|
|
|
const domainObject = displayLayoutContext.item;
|
|
const keyString = this.#openmct.objects.makeKeyString(domainObject.identifier);
|
|
|
|
return {
|
|
control: 'button',
|
|
domainObject,
|
|
icon: ICON_GRID_SHOW,
|
|
method: () => {
|
|
this.#openmct.objectViews.emit(
|
|
`${CONTEXT_ACTION}:${keyString}`,
|
|
CONTEXT_ACTIONS.TOGGLE_GRID
|
|
);
|
|
|
|
this.icon = this.icon === ICON_GRID_SHOW ? ICON_GRID_HIDE : ICON_GRID_SHOW;
|
|
},
|
|
secondary: true
|
|
};
|
|
}
|
|
|
|
#getSeparator() {
|
|
return {
|
|
control: 'separator'
|
|
};
|
|
}
|
|
|
|
#isMainLayoutSelected(selectionPath) {
|
|
let selectedObject = selectionPath[0].context.item;
|
|
|
|
return (
|
|
selectedObject && selectedObject.type === 'layout' && !selectionPath[0].context.layoutItem
|
|
);
|
|
}
|
|
|
|
#showForm(formStructure, name, selection) {
|
|
const domainObject = selection[0][0].context.item;
|
|
const keyString = this.#openmct.objects.makeKeyString(domainObject.identifier);
|
|
this.#openmct.forms.showForm(formStructure).then((changes) => {
|
|
this.#openmct.objectViews.emit(
|
|
`${CONTEXT_ACTION}:${keyString}`,
|
|
CONTEXT_ACTIONS.ADD_ELEMENT,
|
|
name,
|
|
changes,
|
|
selection
|
|
);
|
|
});
|
|
}
|
|
|
|
toolbar(selectedObjects) {
|
|
if (this.#isMainLayoutSelected(selectedObjects[0])) {
|
|
return [this.#getToggleGridButton(selectedObjects), this.#getAddButton(selectedObjects)];
|
|
}
|
|
|
|
let toolbar = {
|
|
'add-menu': [],
|
|
text: [],
|
|
url: [],
|
|
viewSwitcher: [],
|
|
'toggle-frame': [],
|
|
'display-mode': [],
|
|
'telemetry-value': [],
|
|
style: [],
|
|
'unit-toggle': [],
|
|
position: [],
|
|
duplicate: [],
|
|
remove: [],
|
|
'toggle-grid': []
|
|
};
|
|
|
|
selectedObjects.forEach((selectionPath) => {
|
|
let selectedParent = selectionPath[1].context.item;
|
|
let layoutItem = selectionPath[0].context.layoutItem;
|
|
|
|
if (!layoutItem || selectedParent.locked) {
|
|
return;
|
|
}
|
|
|
|
if (layoutItem.type === 'subobject-view') {
|
|
if (toolbar['add-menu'].length === 0 && selectionPath[0].context.item.type === 'layout') {
|
|
toolbar['add-menu'] = [this.#getAddButton(selectedObjects, selectionPath)];
|
|
}
|
|
|
|
if (toolbar['toggle-frame'].length === 0) {
|
|
toolbar['toggle-frame'] = [this.#getToggleFrameButton(selectedParent, selectedObjects)];
|
|
}
|
|
|
|
if (toolbar.position.length === 0) {
|
|
toolbar.position = [
|
|
this.#getStackOrder(selectedParent, selectionPath, selectedObjects),
|
|
this.#getSeparator(),
|
|
this.#getXInput(selectedParent, selectedObjects),
|
|
this.#getYInput(selectedParent, selectedObjects),
|
|
this.#getHeightInput(selectedParent, selectedObjects),
|
|
this.#getWidthInput(selectedParent, selectedObjects)
|
|
];
|
|
}
|
|
|
|
if (toolbar.remove.length === 0) {
|
|
toolbar.remove = [this.#getRemoveButton(selectedParent, selectionPath, selectedObjects)];
|
|
}
|
|
|
|
if (toolbar.viewSwitcher.length === 0) {
|
|
toolbar.viewSwitcher = [
|
|
this.#getViewSwitcherMenu(selectedParent, selectionPath, selectedObjects)
|
|
];
|
|
}
|
|
} else if (layoutItem.type === 'telemetry-view') {
|
|
if (toolbar['display-mode'].length === 0) {
|
|
toolbar['display-mode'] = [this.#getDisplayModeMenu(selectedParent, selectedObjects)];
|
|
}
|
|
|
|
if (toolbar['telemetry-value'].length === 0) {
|
|
toolbar['telemetry-value'] = [
|
|
this.#getTelemetryValueMenu(selectionPath, selectedObjects)
|
|
];
|
|
}
|
|
|
|
if (toolbar['unit-toggle'].length === 0) {
|
|
let toggleUnitsButton = this.#getToggleUnitsButton(selectedParent, selectedObjects);
|
|
if (toggleUnitsButton) {
|
|
toolbar['unit-toggle'] = [toggleUnitsButton];
|
|
}
|
|
}
|
|
|
|
if (toolbar.position.length === 0) {
|
|
toolbar.position = [
|
|
this.#getStackOrder(selectedParent, selectionPath, selectedObjects),
|
|
this.#getSeparator(),
|
|
this.#getXInput(selectedParent, selectedObjects),
|
|
this.#getYInput(selectedParent, selectedObjects),
|
|
this.#getHeightInput(selectedParent, selectedObjects),
|
|
this.#getWidthInput(selectedParent, selectedObjects)
|
|
];
|
|
}
|
|
|
|
if (toolbar.remove.length === 0) {
|
|
toolbar.remove = [this.#getRemoveButton(selectedParent, selectionPath, selectedObjects)];
|
|
}
|
|
|
|
if (toolbar.viewSwitcher.length === 0) {
|
|
toolbar.viewSwitcher = [
|
|
this.#getViewSwitcherMenu(selectedParent, selectionPath, selectedObjects)
|
|
];
|
|
}
|
|
} else if (layoutItem.type === 'text-view') {
|
|
if (toolbar.position.length === 0) {
|
|
toolbar.position = [
|
|
this.#getStackOrder(selectedParent, selectionPath, selectedObjects),
|
|
this.#getSeparator(),
|
|
this.#getXInput(selectedParent, selectedObjects),
|
|
this.#getYInput(selectedParent, selectedObjects),
|
|
this.#getHeightInput(selectedParent, selectedObjects),
|
|
this.#getWidthInput(selectedParent, selectedObjects)
|
|
];
|
|
}
|
|
|
|
if (toolbar.text.length === 0) {
|
|
toolbar.text = [this.#getTextButton(selectedParent, selectedObjects)];
|
|
}
|
|
|
|
if (toolbar.remove.length === 0) {
|
|
toolbar.remove = [this.#getRemoveButton(selectedParent, selectionPath, selectedObjects)];
|
|
}
|
|
} else if (layoutItem.type === 'box-view' || layoutItem.type === 'ellipse-view') {
|
|
if (toolbar.position.length === 0) {
|
|
toolbar.position = [
|
|
this.#getStackOrder(selectedParent, selectionPath, selectedObjects),
|
|
this.#getSeparator(),
|
|
this.#getXInput(selectedParent, selectedObjects),
|
|
this.#getYInput(selectedParent, selectedObjects),
|
|
this.#getHeightInput(selectedParent, selectedObjects),
|
|
this.#getWidthInput(selectedParent, selectedObjects)
|
|
];
|
|
}
|
|
|
|
if (toolbar.remove.length === 0) {
|
|
toolbar.remove = [this.#getRemoveButton(selectedParent, selectionPath, selectedObjects)];
|
|
}
|
|
} else if (layoutItem.type === 'image-view') {
|
|
if (toolbar.position.length === 0) {
|
|
toolbar.position = [
|
|
this.#getStackOrder(selectedParent, selectionPath, selectedObjects),
|
|
this.#getSeparator(),
|
|
this.#getXInput(selectedParent, selectedObjects),
|
|
this.#getYInput(selectedParent, selectedObjects),
|
|
this.#getHeightInput(selectedParent, selectedObjects),
|
|
this.#getWidthInput(selectedParent, selectedObjects)
|
|
];
|
|
}
|
|
|
|
if (toolbar.remove.length === 0) {
|
|
toolbar.remove = [this.#getRemoveButton(selectedParent, selectionPath, selectedObjects)];
|
|
}
|
|
} else if (layoutItem.type === 'line-view') {
|
|
if (toolbar.position.length === 0) {
|
|
toolbar.position = [
|
|
this.#getStackOrder(selectedParent, selectionPath),
|
|
this.#getSeparator(),
|
|
this.#getXInput(selectedParent, selectedObjects),
|
|
this.#getYInput(selectedParent, selectedObjects),
|
|
this.#getX2Input(selectedParent, selectedObjects),
|
|
this.#getY2Input(selectedParent, selectedObjects)
|
|
];
|
|
}
|
|
|
|
if (toolbar.remove.length === 0) {
|
|
toolbar.remove = [this.#getRemoveButton(selectedParent, selectionPath, selectedObjects)];
|
|
}
|
|
}
|
|
|
|
if (toolbar.duplicate.length === 0) {
|
|
toolbar.duplicate = [
|
|
this.#getDuplicateButton(selectedParent, selectionPath, selectedObjects)
|
|
];
|
|
}
|
|
|
|
if (toolbar['toggle-grid'].length === 0) {
|
|
toolbar['toggle-grid'] = [this.#getToggleGridButton(selectedObjects, selectionPath)];
|
|
}
|
|
});
|
|
|
|
let toolbarArray = Object.values(toolbar);
|
|
|
|
return _.flatten(
|
|
toolbarArray.reduce((accumulator, group, index) => {
|
|
group = group.filter((control) => control !== undefined);
|
|
|
|
if (group.length > 0) {
|
|
accumulator.push(group);
|
|
|
|
if (index < toolbarArray.length - 1) {
|
|
accumulator.push(this.#getSeparator());
|
|
}
|
|
}
|
|
|
|
return accumulator;
|
|
}, [])
|
|
);
|
|
}
|
|
}
|