mirror of
https://github.com/nasa/openmct.git
synced 2025-06-14 21:28:12 +00:00
Display layout alphanumeric (#2203)
* Support displaying and adding telemerty points in display layouts. * Create TelemetryView component. Also disable the toolbar frame button for telemetry objects. * Add 'components' directory and move the toolbar provider definition to a separate file. * Saving work * Saving work * Saving work * Fix telemetryClass * Fixes for .no-frame in new markup structure - CSS cleaned up and reorganized; - Added .c-telemetry-view classes; * Add computed properties for hiding label and value. * Filter value meta data based on the item config display mode. * Add drop down menus for display mode and value * Add toolbar controls for telemerty points * Set border and fill related styles on telemetry view instead of layout item * Refinements to telemetry view - Stoke and fill styling now work; - Internal element layout now much better when sizing in a Layout frame; - Tweaked color of frame border while editing; * Prevents adding a new (panel) object if it's already in the composition. * Fix for jumping edit area - Removed v-if from Toolbar.vue; - Refined c-toolbar styling; - TODO: don't include toolbar component when not editing, and for components that don't use a toolbar; * Add a separator toolbar control * Check for domainObject being on the toolbar item as not all controls have that property * Hide 'no fill' option from the text palette. Modify the color-picker component to say 'No border' for stroke palette. * Move the listener for hasFrame to the subobject view configuration * Fixes for toolbar-separator - New mixin; - Corrected markup for separator; - New class for .c-toolbar__separator; - Updated DisplayLayoutToolbar.js to include separators in the right spots; * Get type from item. * Include copyright notice. * Use arrow function for consistency and define a TEXT_SIZE constant. * Use composition API to add non-telemetry objects instead of relying on the drop handler. Display a blocking dialog if an existing non-telemetry object is dropped. * Fix text color picker icon * Address reviewer's feedback * Load the composition and update addObject() to render existing panels as well. Also, cache the telemetry value formatter. * Add listener for changes to time bounds. * Code cleanup * Use getFormatMap() to store formats. Reset telemetry value and class before fetching new data. * Fix a typo * Define telemetry class and value as computed properties. * Change context object definition * Look at the telemetry metadata to find a good default for the value key instead of defaulting to 'sin'. Also, make formats reactive. * Use let instead of var.
This commit is contained in:
committed by
Pete Richards
parent
55d3ab5e8a
commit
d13d59bfa0
@ -1,312 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2018, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
<template>
|
|
||||||
<div class="l-layout"
|
|
||||||
@dragover="handleDragOver"
|
|
||||||
@click="bypassSelection"
|
|
||||||
@drop="handleDrop">
|
|
||||||
<div class="l-layout__object">
|
|
||||||
<!-- Background grid -->
|
|
||||||
<div class="l-layout__grid-holder c-grid"
|
|
||||||
v-if="!drilledIn">
|
|
||||||
<div class="c-grid__x l-grid l-grid-x"
|
|
||||||
v-if="gridSize[0] >= 3"
|
|
||||||
:style="[{ backgroundSize: gridSize[0] + 'px 100%' }]">
|
|
||||||
</div>
|
|
||||||
<div class="c-grid__y l-grid l-grid-y"
|
|
||||||
v-if="gridSize[1] >= 3"
|
|
||||||
:style="[{ backgroundSize: '100%' + gridSize[1] + 'px' }]"></div>
|
|
||||||
</div>
|
|
||||||
<layout-frame v-for="item in frameItems"
|
|
||||||
class="l-layout__frame"
|
|
||||||
:key="item.id"
|
|
||||||
:item="item"
|
|
||||||
:gridSize="gridSize"
|
|
||||||
@drilledIn="updateDrilledInState"
|
|
||||||
@dragInProgress="updatePosition"
|
|
||||||
@endDrag="endDrag">
|
|
||||||
</layout-frame>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "~styles/sass-base";
|
|
||||||
|
|
||||||
.l-layout {
|
|
||||||
@include abs();
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
&__grid-holder {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__object {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
&__frame {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.l-shell__main-container {
|
|
||||||
> .l-layout {
|
|
||||||
[s-selected] {
|
|
||||||
border: $browseBorderSelected;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Styles moved to _global.scss;
|
|
||||||
</style>
|
|
||||||
|
|
||||||
|
|
||||||
<script>
|
|
||||||
import LayoutFrame from './LayoutFrame.vue';
|
|
||||||
|
|
||||||
const DEFAULT_GRID_SIZE = [32, 32],
|
|
||||||
DEFAULT_DIMENSIONS = [12, 8],
|
|
||||||
DEFAULT_POSITION = [0, 0],
|
|
||||||
MINIMUM_FRAME_SIZE = [320, 180],
|
|
||||||
DEFAULT_HIDDEN_FRAME_TYPES = [
|
|
||||||
'hyperlink'
|
|
||||||
];
|
|
||||||
|
|
||||||
export default {
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
gridSize: [],
|
|
||||||
frameItems: [],
|
|
||||||
frames: [],
|
|
||||||
frameStyles: [],
|
|
||||||
rawPositions: {},
|
|
||||||
drilledIn: undefined
|
|
||||||
}
|
|
||||||
},
|
|
||||||
inject: ['openmct'],
|
|
||||||
props: ['domainObject'],
|
|
||||||
components: {
|
|
||||||
LayoutFrame
|
|
||||||
},
|
|
||||||
created: function () {
|
|
||||||
this.newDomainObject = this.domainObject;
|
|
||||||
this.gridSize = this.newDomainObject.layoutGrid || DEFAULT_GRID_SIZE;
|
|
||||||
this.composition = this.openmct.composition.get(this.newDomainObject);
|
|
||||||
this.Listeners = [];
|
|
||||||
let panels = (((this.newDomainObject.configuration || {}).layout || {}).panels || {});
|
|
||||||
|
|
||||||
if (this.composition !== undefined) {
|
|
||||||
this.composition.load().then((composition) => {
|
|
||||||
composition.forEach(function (domainObject) {
|
|
||||||
this.readLayoutConfiguration(domainObject, panels);
|
|
||||||
this.makeFrameItem(domainObject, false);
|
|
||||||
}.bind(this));
|
|
||||||
this.composition.on('add', this.onAddComposition);
|
|
||||||
this.composition.on('remove', this.onRemoveComposition);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.unlisten = this.openmct.objects.observe(this.newDomainObject, '*', function (obj) {
|
|
||||||
this.newDomainObject = JSON.parse(JSON.stringify(obj));
|
|
||||||
this.gridSize = this.newDomainObject.layoutGrid || DEFAULT_GRID_SIZE;;
|
|
||||||
}.bind(this));
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
readLayoutConfiguration(domainObject, panels) {
|
|
||||||
let id = this.openmct.objects.makeKeyString(domainObject.identifier);
|
|
||||||
this.rawPositions[id] = {
|
|
||||||
position: panels[id].position || DEFAULT_POSITION,
|
|
||||||
dimensions: panels[id].dimensions || this.defaultDimensions()
|
|
||||||
};
|
|
||||||
this.frameStyles[id] = this.convertPosition(this.rawPositions[id]);
|
|
||||||
this.frames[id] = panels[id].hasOwnProperty('hasFrame') ?
|
|
||||||
panels[id].hasFrame :
|
|
||||||
this.hasFrameByDefault(domainObject.type);
|
|
||||||
},
|
|
||||||
makeFrameItem(domainObject, initSelect) {
|
|
||||||
let id = this.openmct.objects.makeKeyString(domainObject.identifier);
|
|
||||||
this.frameItems.push({
|
|
||||||
id: id,
|
|
||||||
hasFrame: this.frames[id],
|
|
||||||
domainObject,
|
|
||||||
style: this.frameStyles[id],
|
|
||||||
drilledIn: this.isDrilledIn(id),
|
|
||||||
initSelect: initSelect,
|
|
||||||
rawPosition: this.rawPositions[id]
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onAddComposition(domainObject) {
|
|
||||||
let id = this.openmct.objects.makeKeyString(domainObject.identifier);
|
|
||||||
this.rawPositions[id] = {
|
|
||||||
position: [
|
|
||||||
Math.floor(this.droppedObjectPosition.x / this.gridSize[0]),
|
|
||||||
Math.floor(this.droppedObjectPosition.y / this.gridSize[1])
|
|
||||||
],
|
|
||||||
dimensions: this.defaultDimensions()
|
|
||||||
};
|
|
||||||
this.frameStyles[id] = this.convertPosition(this.rawPositions[id]);
|
|
||||||
this.frames[id] = this.hasFrameByDefault(domainObject.type);
|
|
||||||
|
|
||||||
let newPanel = this.rawPositions[id];
|
|
||||||
newPanel.hasFrame = this.frames[id];
|
|
||||||
this.mutate("configuration.layout.panels[" + id + "]", newPanel);
|
|
||||||
this.makeFrameItem(domainObject, true);
|
|
||||||
},
|
|
||||||
onRemoveComposition(identifier) {
|
|
||||||
// TODO: remove the object from frameItems
|
|
||||||
},
|
|
||||||
defaultDimensions() {
|
|
||||||
let gridSize = this.gridSize;
|
|
||||||
return MINIMUM_FRAME_SIZE.map(function (min, i) {
|
|
||||||
return Math.max(
|
|
||||||
Math.ceil(min / gridSize[i]),
|
|
||||||
DEFAULT_DIMENSIONS[i]
|
|
||||||
);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
convertPosition(raw) {
|
|
||||||
return {
|
|
||||||
left: (this.gridSize[0] * raw.position[0]) + 'px',
|
|
||||||
top: (this.gridSize[1] * raw.position[1]) + 'px',
|
|
||||||
width: (this.gridSize[0] * raw.dimensions[0]) + 'px',
|
|
||||||
height: (this.gridSize[1] * raw.dimensions[1]) + 'px',
|
|
||||||
minWidth: (this.gridSize[0] * raw.dimensions[0]) + 'px',
|
|
||||||
minHeight: (this.gridSize[1] * raw.dimensions[1]) + 'px'
|
|
||||||
};
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Checks if the frame should be hidden or not.
|
|
||||||
*
|
|
||||||
* @param type the domain object type
|
|
||||||
* @return {boolean} true if the object should have
|
|
||||||
* frame by default, false, otherwise
|
|
||||||
*/
|
|
||||||
hasFrameByDefault(type) {
|
|
||||||
return DEFAULT_HIDDEN_FRAME_TYPES.indexOf(type) === -1;
|
|
||||||
},
|
|
||||||
setSelection(selection) {
|
|
||||||
if (selection.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.removeListeners();
|
|
||||||
let domainObject = selection[0].context.item;
|
|
||||||
|
|
||||||
if (selection[1] && domainObject) {
|
|
||||||
this.attachSelectionListeners(domainObject.identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateDrilledInState();
|
|
||||||
},
|
|
||||||
attachSelectionListeners(identifier) {
|
|
||||||
let id = this.openmct.objects.makeKeyString(identifier);
|
|
||||||
let path = "configuration.layout.panels[" + id + "]";
|
|
||||||
this.listeners.push(this.openmct.objects.observe(this.newDomainObject, path + ".hasFrame", function (newValue) {
|
|
||||||
this.frameItems.forEach(function (item) {
|
|
||||||
if (item.id === id) {
|
|
||||||
item.hasFrame = newValue;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.frames[id] = newValue;
|
|
||||||
}.bind(this)));
|
|
||||||
},
|
|
||||||
updateDrilledInState(id) {
|
|
||||||
this.drilledIn = id;
|
|
||||||
this.frameItems.forEach(function (item) {
|
|
||||||
item.drilledIn = item.id === id;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
isDrilledIn(id) {
|
|
||||||
return this.drilledIn === id;
|
|
||||||
},
|
|
||||||
updatePosition(id, newPosition) {
|
|
||||||
let newStyle = this.convertPosition(newPosition);
|
|
||||||
this.frameStyles[id] = newStyle;
|
|
||||||
this.rawPositions[id] = newPosition;
|
|
||||||
this.frameItems.forEach(function (item) {
|
|
||||||
if (item.id === id) {
|
|
||||||
item.style = newStyle;
|
|
||||||
item.rawPosition = newPosition;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
bypassSelection($event) {
|
|
||||||
if (this.dragInProgress) {
|
|
||||||
if ($event) {
|
|
||||||
$event.stopImmediatePropagation();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
endDrag(id) {
|
|
||||||
this.dragInProgress = true;
|
|
||||||
setTimeout(function () {
|
|
||||||
this.dragInProgress = false;
|
|
||||||
}.bind(this), 0);
|
|
||||||
|
|
||||||
let path = "configuration.layout.panels[" + id + "]";
|
|
||||||
this.mutate(path + ".dimensions", this.rawPositions[id].dimensions);
|
|
||||||
this.mutate(path + ".position", this.rawPositions[id].position);
|
|
||||||
},
|
|
||||||
mutate(path, value) {
|
|
||||||
this.openmct.objects.mutate(this.newDomainObject, path, value);
|
|
||||||
},
|
|
||||||
handleDrop($event) {
|
|
||||||
$event.preventDefault();
|
|
||||||
|
|
||||||
let child = JSON.parse($event.dataTransfer.getData('domainObject'));
|
|
||||||
|
|
||||||
let elementRect = this.$el.getBoundingClientRect();
|
|
||||||
this.droppedObjectPosition = {
|
|
||||||
x: $event.pageX - elementRect.left,
|
|
||||||
y: $event.pageY - elementRect.top
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleDragOver($event){
|
|
||||||
$event.preventDefault();
|
|
||||||
},
|
|
||||||
removeListeners() {
|
|
||||||
if (this.listeners) {
|
|
||||||
this.listeners.forEach(function (l) {
|
|
||||||
l();
|
|
||||||
})
|
|
||||||
}
|
|
||||||
this.listeners = [];
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.openmct.selection.on('change', this.setSelection);
|
|
||||||
},
|
|
||||||
destroyed: function () {
|
|
||||||
this.composition.off('add', this.onAddComposition);
|
|
||||||
this.composition.off('remove', this.onRemoveComposition);
|
|
||||||
this.openmct.off('change', this.selection);
|
|
||||||
this.unlisten();
|
|
||||||
this.removeListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
|
151
src/plugins/displayLayout/DisplayLayoutToolbar.js
Normal file
151
src/plugins/displayLayout/DisplayLayoutToolbar.js
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define([], function () {
|
||||||
|
|
||||||
|
function DisplayLayoutToolbar(openmct) {
|
||||||
|
return {
|
||||||
|
name: "Display Layout Toolbar",
|
||||||
|
key: "layout",
|
||||||
|
description: "A toolbar for objects inside a display layout.",
|
||||||
|
forSelection: function (selection) {
|
||||||
|
// Apply the layout toolbar if the selected object is inside a layout,
|
||||||
|
// and in edit mode.
|
||||||
|
return (selection &&
|
||||||
|
selection[1] &&
|
||||||
|
selection[1].context.item &&
|
||||||
|
selection[1].context.item.type === 'layout' &&
|
||||||
|
openmct.editor.isEditing());
|
||||||
|
},
|
||||||
|
toolbar: function (selection) {
|
||||||
|
let domainObject = selection[1].context.item;
|
||||||
|
let layoutItem = selection[0].context.layoutItem;
|
||||||
|
|
||||||
|
if (layoutItem && layoutItem.type === 'telemetry-view') {
|
||||||
|
let path = "configuration.alphanumerics[" + layoutItem.config.alphanumeric.index + "]";
|
||||||
|
let metadata = openmct.telemetry.getMetadata(layoutItem.domainObject);
|
||||||
|
const TEXT_SIZE = [9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96];
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
control: "select-menu",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".displayMode",
|
||||||
|
title: "Set display mode",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Label + Value',
|
||||||
|
value: 'all'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Label only",
|
||||||
|
value: "label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Value only",
|
||||||
|
value: "value"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "separator"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "select-menu",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".value",
|
||||||
|
title: "Set value",
|
||||||
|
options: metadata.values().map(value => {
|
||||||
|
return {
|
||||||
|
name: value.name,
|
||||||
|
value: value.key
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "separator"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "color-picker",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".fill",
|
||||||
|
icon: "icon-paint-bucket",
|
||||||
|
title: "Set fill color"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "color-picker",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".stroke",
|
||||||
|
icon: "icon-line-horz",
|
||||||
|
title: "Set border color"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "color-picker",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".color",
|
||||||
|
icon: "icon-font",
|
||||||
|
mandatory: true,
|
||||||
|
title: "Set text color",
|
||||||
|
preventNone: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "separator"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
control: "select-menu",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: path + ".size",
|
||||||
|
title: "Set text size",
|
||||||
|
options: TEXT_SIZE.map(size => {
|
||||||
|
return {
|
||||||
|
value: size + "px"
|
||||||
|
};
|
||||||
|
})
|
||||||
|
},
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
control: "toggle-button",
|
||||||
|
domainObject: domainObject,
|
||||||
|
property: "configuration.panels[" + layoutItem.id + "].hasFrame",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
value: false,
|
||||||
|
icon: 'icon-frame-hide',
|
||||||
|
title: "Hide frame"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
icon: 'icon-frame-show',
|
||||||
|
title: "Show frame"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DisplayLayoutToolbar;
|
||||||
|
});
|
@ -29,9 +29,8 @@ define(function () {
|
|||||||
initialize(domainObject) {
|
initialize(domainObject) {
|
||||||
domainObject.composition = [];
|
domainObject.composition = [];
|
||||||
domainObject.configuration = {
|
domainObject.configuration = {
|
||||||
layout: {
|
panels: {},
|
||||||
panels: {}
|
alphanumerics: []
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
74
src/plugins/displayLayout/SubobjectViewConfiguration.js
Normal file
74
src/plugins/displayLayout/SubobjectViewConfiguration.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define([],
|
||||||
|
function () {
|
||||||
|
class SubobjectViewConfiguration {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param domainObject the domain object to mutate.
|
||||||
|
* @param id
|
||||||
|
* @param rawPosition
|
||||||
|
* @param openmct
|
||||||
|
*/
|
||||||
|
constructor(domainObject, id, hasFrame, rawPosition, openmct) {
|
||||||
|
this.domainObject = domainObject;
|
||||||
|
this.id = id;
|
||||||
|
this.hasFrame = hasFrame;
|
||||||
|
this.rawPosition = rawPosition;
|
||||||
|
this.openmct = openmct;
|
||||||
|
this.mutatePosition = this.mutatePosition.bind(this);
|
||||||
|
this.listeners = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
mutatePosition() {
|
||||||
|
let path = "configuration.panels[" + this.id + "]";
|
||||||
|
this.mutate(path + ".dimensions", this.rawPosition.dimensions);
|
||||||
|
this.mutate(path + ".position", this.rawPosition.position);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutate(path, value) {
|
||||||
|
this.openmct.objects.mutate(this.domainObject, path, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
attachListeners() {
|
||||||
|
let path = "configuration.panels[" + this.id + "].hasFrame";
|
||||||
|
this.listeners.push(this.openmct.objects.observe(this.domainObject, path, function (newValue) {
|
||||||
|
this.hasFrame = newValue;
|
||||||
|
}.bind(this)));
|
||||||
|
|
||||||
|
this.listeners.push(this.openmct.objects.observe(this.domainObject, '*', function (obj) {
|
||||||
|
this.domainObject = JSON.parse(JSON.stringify(obj));
|
||||||
|
}.bind(this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeListeners() {
|
||||||
|
this.listeners.forEach(listener => {
|
||||||
|
listener();
|
||||||
|
});
|
||||||
|
this.listeners = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SubobjectViewConfiguration;
|
||||||
|
}
|
||||||
|
);
|
84
src/plugins/displayLayout/TelemetryViewConfiguration.js
Normal file
84
src/plugins/displayLayout/TelemetryViewConfiguration.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
define([],
|
||||||
|
function () {
|
||||||
|
class TelemetryViewConfiguration {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param domainObject the domain object to mutate.
|
||||||
|
* @param alphanumeric
|
||||||
|
* @param rawPosition
|
||||||
|
* @param openmct
|
||||||
|
*/
|
||||||
|
constructor(domainObject, alphanumeric, rawPosition, openmct) {
|
||||||
|
this.domainObject = domainObject;
|
||||||
|
this.alphanumeric = alphanumeric;
|
||||||
|
this.rawPosition = rawPosition;
|
||||||
|
this.openmct = openmct;
|
||||||
|
this.mutatePosition = this.mutatePosition.bind(this);
|
||||||
|
this.listeners = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
mutatePosition() {
|
||||||
|
let path = "configuration.alphanumerics[" + this.alphanumeric.index + "]";
|
||||||
|
this.mutate(path + ".dimensions", this.rawPosition.dimensions);
|
||||||
|
this.mutate(path + ".position", this.rawPosition.position);
|
||||||
|
}
|
||||||
|
|
||||||
|
attachListeners() {
|
||||||
|
let path = "configuration.alphanumerics[" + this.alphanumeric.index + "]";
|
||||||
|
[
|
||||||
|
'displayMode',
|
||||||
|
'value',
|
||||||
|
'fill',
|
||||||
|
'stroke',
|
||||||
|
'color',
|
||||||
|
'size'
|
||||||
|
].forEach(property => {
|
||||||
|
this.listeners.push(
|
||||||
|
this.openmct.objects.observe(this.domainObject, path + "." + property, function (newValue) {
|
||||||
|
this.alphanumeric[property] = newValue;
|
||||||
|
}.bind(this))
|
||||||
|
);
|
||||||
|
});
|
||||||
|
this.listeners.push(this.openmct.objects.observe(this.domainObject, '*', function (obj) {
|
||||||
|
this.domainObject = JSON.parse(JSON.stringify(obj));
|
||||||
|
}.bind(this)));
|
||||||
|
}
|
||||||
|
|
||||||
|
removeListeners() {
|
||||||
|
this.listeners.forEach(listener => {
|
||||||
|
listener();
|
||||||
|
});
|
||||||
|
this.listeners = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
mutate(path, value) {
|
||||||
|
this.openmct.objects.mutate(this.domainObject, path, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return TelemetryViewConfiguration;
|
||||||
|
}
|
||||||
|
);
|
380
src/plugins/displayLayout/components/DisplayLayout.vue
Normal file
380
src/plugins/displayLayout/components/DisplayLayout.vue
Normal file
@ -0,0 +1,380 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="l-layout"
|
||||||
|
@dragover="handleDragOver"
|
||||||
|
@click="bypassSelection"
|
||||||
|
@drop="handleDrop">
|
||||||
|
<div class="l-layout__object">
|
||||||
|
<!-- Background grid -->
|
||||||
|
<div class="l-layout__grid-holder c-grid"
|
||||||
|
v-if="!drilledIn">
|
||||||
|
<div class="c-grid__x l-grid l-grid-x"
|
||||||
|
v-if="gridSize[0] >= 3"
|
||||||
|
:style="[{ backgroundSize: gridSize[0] + 'px 100%' }]">
|
||||||
|
</div>
|
||||||
|
<div class="c-grid__y l-grid l-grid-y"
|
||||||
|
v-if="gridSize[1] >= 3"
|
||||||
|
:style="[{ backgroundSize: '100%' + gridSize[1] + 'px' }]"></div>
|
||||||
|
</div>
|
||||||
|
<layout-item v-for="(item, index) in layoutItems"
|
||||||
|
class="l-layout__frame"
|
||||||
|
:key="index"
|
||||||
|
:item="item"
|
||||||
|
:gridSize="gridSize"
|
||||||
|
@drilledIn="updateDrilledInState"
|
||||||
|
@dragInProgress="updatePosition"
|
||||||
|
@endDrag="endDrag">
|
||||||
|
</layout-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
|
.l-layout {
|
||||||
|
@include abs();
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
&__grid-holder {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__object {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__frame {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-shell__main-container {
|
||||||
|
> .l-layout {
|
||||||
|
[s-selected] {
|
||||||
|
border: $browseBorderSelected;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Styles moved to _global.scss;
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import LayoutItem from './LayoutItem.vue';
|
||||||
|
import TelemetryViewConfiguration from './../TelemetryViewConfiguration.js'
|
||||||
|
import SubobjectViewConfiguration from './../SubobjectViewConfiguration.js'
|
||||||
|
|
||||||
|
const DEFAULT_GRID_SIZE = [32, 32],
|
||||||
|
DEFAULT_DIMENSIONS = [12, 8],
|
||||||
|
DEFAULT_TELEMETRY_DIMENSIONS = [2, 1],
|
||||||
|
DEFAULT_POSITION = [0, 0],
|
||||||
|
MINIMUM_FRAME_SIZE = [320, 180],
|
||||||
|
DEFAULT_HIDDEN_FRAME_TYPES = [
|
||||||
|
'hyperlink'
|
||||||
|
];
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
gridSize: [],
|
||||||
|
layoutItems: [],
|
||||||
|
drilledIn: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
inject: ['openmct'],
|
||||||
|
props: ['domainObject'],
|
||||||
|
components: {
|
||||||
|
LayoutItem
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getAlphanumerics() {
|
||||||
|
let alphanumerics = this.newDomainObject.configuration.alphanumerics || [];
|
||||||
|
alphanumerics.forEach((alphanumeric, index) => {
|
||||||
|
alphanumeric.index = index;
|
||||||
|
this.makeTelemetryItem(alphanumeric, false);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
makeFrameItem(panel, initSelect) {
|
||||||
|
let rawPosition = {
|
||||||
|
position: panel.position,
|
||||||
|
dimensions: panel.dimensions
|
||||||
|
};
|
||||||
|
let style = this.convertPosition(rawPosition);
|
||||||
|
let id = this.openmct.objects.makeKeyString(panel.domainObject.identifier);
|
||||||
|
let config = new SubobjectViewConfiguration(
|
||||||
|
this.newDomainObject, id, panel.hasFrame, rawPosition, openmct);
|
||||||
|
|
||||||
|
this.layoutItems.push({
|
||||||
|
id: id,
|
||||||
|
domainObject: panel.domainObject,
|
||||||
|
style: style,
|
||||||
|
drilledIn: this.isItemDrilledIn(id),
|
||||||
|
initSelect: initSelect,
|
||||||
|
type: 'subobject-view',
|
||||||
|
config: config
|
||||||
|
});
|
||||||
|
},
|
||||||
|
makeTelemetryItem(alphanumeric, initSelect) {
|
||||||
|
let rawPosition = {
|
||||||
|
position: alphanumeric.position,
|
||||||
|
dimensions: alphanumeric.dimensions
|
||||||
|
};
|
||||||
|
let style = this.convertPosition(rawPosition);
|
||||||
|
let id = this.openmct.objects.makeKeyString(alphanumeric.identifier);
|
||||||
|
|
||||||
|
this.openmct.objects.get(id).then(domainObject => {
|
||||||
|
let config = new TelemetryViewConfiguration(
|
||||||
|
this.newDomainObject, alphanumeric, rawPosition, openmct);
|
||||||
|
|
||||||
|
this.layoutItems.push({
|
||||||
|
id: id,
|
||||||
|
domainObject: domainObject,
|
||||||
|
style: style,
|
||||||
|
initSelect: initSelect,
|
||||||
|
alphanumeric: alphanumeric,
|
||||||
|
type: 'telemetry-view',
|
||||||
|
config: config
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
getSubobjectDefaultDimensions() {
|
||||||
|
let gridSize = this.gridSize;
|
||||||
|
return MINIMUM_FRAME_SIZE.map(function (min, i) {
|
||||||
|
return Math.max(
|
||||||
|
Math.ceil(min / gridSize[i]),
|
||||||
|
DEFAULT_DIMENSIONS[i]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
convertPosition(raw) {
|
||||||
|
return {
|
||||||
|
left: (this.gridSize[0] * raw.position[0]) + 'px',
|
||||||
|
top: (this.gridSize[1] * raw.position[1]) + 'px',
|
||||||
|
width: (this.gridSize[0] * raw.dimensions[0]) + 'px',
|
||||||
|
height: (this.gridSize[1] * raw.dimensions[1]) + 'px',
|
||||||
|
minWidth: (this.gridSize[0] * raw.dimensions[0]) + 'px',
|
||||||
|
minHeight: (this.gridSize[1] * raw.dimensions[1]) + 'px'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Checks if the frame should be hidden or not.
|
||||||
|
*
|
||||||
|
* @param type the domain object type
|
||||||
|
* @return {boolean} true if the object should have
|
||||||
|
* frame by default, false, otherwise
|
||||||
|
*/
|
||||||
|
hasFrameByDefault(type) {
|
||||||
|
return DEFAULT_HIDDEN_FRAME_TYPES.indexOf(type) === -1;
|
||||||
|
},
|
||||||
|
setSelection(selection) {
|
||||||
|
if (selection.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateDrilledInState();
|
||||||
|
},
|
||||||
|
updateDrilledInState(id) {
|
||||||
|
this.drilledIn = id;
|
||||||
|
this.layoutItems.forEach(function (item) {
|
||||||
|
if (item.type === 'subobject-view') {
|
||||||
|
item.drilledIn = item.id === id;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
isItemDrilledIn(id) {
|
||||||
|
return this.drilledIn === id;
|
||||||
|
},
|
||||||
|
updatePosition(item, newPosition) {
|
||||||
|
let newStyle = this.convertPosition(newPosition);
|
||||||
|
item.config.rawPosition = newPosition;
|
||||||
|
item.style = newStyle;
|
||||||
|
},
|
||||||
|
bypassSelection($event) {
|
||||||
|
if (this.dragInProgress) {
|
||||||
|
if ($event) {
|
||||||
|
$event.stopImmediatePropagation();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
endDrag(item) {
|
||||||
|
this.dragInProgress = true;
|
||||||
|
setTimeout(function () {
|
||||||
|
this.dragInProgress = false;
|
||||||
|
}.bind(this), 0);
|
||||||
|
|
||||||
|
item.config.mutatePosition();
|
||||||
|
},
|
||||||
|
mutate(path, value) {
|
||||||
|
this.openmct.objects.mutate(this.newDomainObject, path, value);
|
||||||
|
},
|
||||||
|
handleDrop($event) {
|
||||||
|
$event.preventDefault();
|
||||||
|
|
||||||
|
let domainObject = JSON.parse($event.dataTransfer.getData('domainObject'));
|
||||||
|
let elementRect = this.$el.getBoundingClientRect();
|
||||||
|
this.droppedObjectPosition = [
|
||||||
|
Math.floor(($event.pageX - elementRect.left) / this.gridSize[0]),
|
||||||
|
Math.floor(($event.pageY - elementRect.top) / this.gridSize[1])
|
||||||
|
];
|
||||||
|
|
||||||
|
if (this.isTelemetry(domainObject)) {
|
||||||
|
this.addAlphanumeric(domainObject, this.droppedObjectPosition);
|
||||||
|
} else {
|
||||||
|
this.checkForDuplicatePanel(domainObject);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
checkForDuplicatePanel(domainObject) {
|
||||||
|
let id = this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||||
|
let panels = this.newDomainObject.configuration.panels;
|
||||||
|
|
||||||
|
if (panels && panels[id]) {
|
||||||
|
let prompt = this.openmct.overlays.dialog({
|
||||||
|
iconClass: 'alert',
|
||||||
|
message: "This item is already in layout and will not be added again.",
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
label: 'OK',
|
||||||
|
callback: function () {
|
||||||
|
prompt.dismiss();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addAlphanumeric(domainObject, position) {
|
||||||
|
let alphanumeric = {
|
||||||
|
identifier: domainObject.identifier,
|
||||||
|
position: position,
|
||||||
|
dimensions: DEFAULT_TELEMETRY_DIMENSIONS,
|
||||||
|
displayMode: 'all',
|
||||||
|
value: this.getDefaultTelemetryValue(domainObject),
|
||||||
|
stroke: "transparent",
|
||||||
|
fill: "",
|
||||||
|
color: "",
|
||||||
|
size: "13px",
|
||||||
|
};
|
||||||
|
let alphanumerics = this.newDomainObject.configuration.alphanumerics || [];
|
||||||
|
alphanumeric.index = alphanumerics.push(alphanumeric) - 1;
|
||||||
|
|
||||||
|
this.mutate("configuration.alphanumerics", alphanumerics);
|
||||||
|
this.makeTelemetryItem(alphanumeric, true);
|
||||||
|
},
|
||||||
|
getDefaultTelemetryValue(domainObject) {
|
||||||
|
let metadata = this.openmct.telemetry.getMetadata(domainObject);
|
||||||
|
let valueMetadata = metadata.valuesForHints(['range'])[0];
|
||||||
|
|
||||||
|
if (valueMetadata === undefined) {
|
||||||
|
valueMetadata = metadata.values().filter(values => {
|
||||||
|
return !(values.hints.domain);
|
||||||
|
})[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueMetadata === undefined) {
|
||||||
|
valueMetadata = metadata.values()[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return valueMetadata.key;
|
||||||
|
},
|
||||||
|
handleDragOver($event){
|
||||||
|
$event.preventDefault();
|
||||||
|
},
|
||||||
|
isTelemetry(domainObject) {
|
||||||
|
if (this.openmct.telemetry.isTelemetryObject(domainObject)
|
||||||
|
&& domainObject.type !== 'summary-widget') {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
addObject(domainObject) {
|
||||||
|
if (!this.isTelemetry(domainObject)) {
|
||||||
|
let panels = this.newDomainObject.configuration.panels,
|
||||||
|
id = this.openmct.objects.makeKeyString(domainObject.identifier),
|
||||||
|
panel = panels[id],
|
||||||
|
mutateObject = false,
|
||||||
|
initSelect = false;
|
||||||
|
|
||||||
|
// If this is a new panel, select it and save the configuration.
|
||||||
|
if (!panel) {
|
||||||
|
panel = {};
|
||||||
|
mutateObject = true;
|
||||||
|
initSelect = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
panel.dimensions = panel.dimensions || this.getSubobjectDefaultDimensions();
|
||||||
|
panel.hasFrame = panel.hasOwnProperty('hasFrame') ?
|
||||||
|
panel.hasFrame :
|
||||||
|
this.hasFrameByDefault(domainObject.type);
|
||||||
|
|
||||||
|
if (this.droppedObjectPosition) {
|
||||||
|
panel.position = this.droppedObjectPosition;
|
||||||
|
this.droppedObjectPosition = undefined;
|
||||||
|
} else {
|
||||||
|
panel.position = panel.position || DEFAULT_POSITION;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mutateObject) {
|
||||||
|
this.mutate("configuration.panels[" + id + "]", panel);
|
||||||
|
}
|
||||||
|
|
||||||
|
panel.domainObject = domainObject;
|
||||||
|
this.makeFrameItem(panel, initSelect);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
removeObject() {
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.newDomainObject = this.domainObject;
|
||||||
|
this.gridSize = this.newDomainObject.layoutGrid || DEFAULT_GRID_SIZE;
|
||||||
|
|
||||||
|
this.unlisten = this.openmct.objects.observe(this.newDomainObject, '*', function (obj) {
|
||||||
|
this.newDomainObject = JSON.parse(JSON.stringify(obj));
|
||||||
|
this.gridSize = this.newDomainObject.layoutGrid || DEFAULT_GRID_SIZE;;
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
this.openmct.selection.on('change', this.setSelection);
|
||||||
|
|
||||||
|
this.composition = this.openmct.composition.get(this.newDomainObject);
|
||||||
|
this.composition.on('add', this.addObject);
|
||||||
|
this.composition.on('remove', this.removeObject);
|
||||||
|
this.composition.load();
|
||||||
|
this.getAlphanumerics();
|
||||||
|
},
|
||||||
|
destroyed: function () {
|
||||||
|
this.openmct.off('change', this.setSelection);
|
||||||
|
this.composition.off('add', this.addObject);
|
||||||
|
this.composition.off('remove', this.removeObject);
|
||||||
|
this.unlisten();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
@ -25,17 +25,8 @@
|
|||||||
:style="item.style"
|
:style="item.style"
|
||||||
:class="classObject"
|
:class="classObject"
|
||||||
@dblclick="drill(item.id, $event)">
|
@dblclick="drill(item.id, $event)">
|
||||||
<div class="c-frame__header">
|
|
||||||
<div class="c-frame__header__start">
|
<component :is="item.type" :item="item"></component>
|
||||||
<div class="c-frame__name icon-object">{{ item.domainObject.name }}</div>
|
|
||||||
<div class="c-frame__context-actions c-disclosure-button"></div>
|
|
||||||
</div>
|
|
||||||
<div class="c-frame__header__end">
|
|
||||||
<div class="c-button icon-expand local-controls--hidden"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<object-view class="c-frame__object-view"
|
|
||||||
:object="item.domainObject"></object-view>
|
|
||||||
|
|
||||||
<!-- Drag handles -->
|
<!-- Drag handles -->
|
||||||
<div class="c-frame-edit">
|
<div class="c-frame-edit">
|
||||||
@ -60,68 +51,11 @@
|
|||||||
.c-frame {
|
.c-frame {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
border-width: 1px;
|
border: 1px solid transparent;
|
||||||
border-color: transparent;
|
|
||||||
|
|
||||||
/*************************** HEADER */
|
|
||||||
&__header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
margin-bottom: $interiorMargin;
|
|
||||||
|
|
||||||
> [class*="__"] {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
> * + * {
|
|
||||||
margin-left: $interiorMargin;
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*="__start"] {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*="__end"] {
|
|
||||||
//justify-content: flex-end;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
|
|
||||||
[class*="button"] {
|
|
||||||
font-size: 0.7em;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&__name {
|
|
||||||
@include ellipsize();
|
|
||||||
flex: 0 1 auto;
|
|
||||||
font-size: 1.2em;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
// Object type icon
|
|
||||||
flex: 0 0 auto;
|
|
||||||
margin-right: $interiorMarginSm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************** OBJECT VIEW */
|
|
||||||
&__object-view {
|
|
||||||
flex: 1 1 auto;
|
|
||||||
overflow: auto;
|
|
||||||
|
|
||||||
.c-object-view {
|
|
||||||
.u-fills-container {
|
|
||||||
// Expand component types that fill a container
|
|
||||||
@include abs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************** NO-FRAME */
|
/*************************** NO-FRAME */
|
||||||
&.no-frame {
|
&.no-frame {
|
||||||
> [class*="__header"] {
|
> [class*="contents"] > [class*="__header"] {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,15 +65,14 @@
|
|||||||
border: 1px solid $colorInteriorBorder;
|
border: 1px solid $colorInteriorBorder;
|
||||||
padding: $interiorMargin;
|
padding: $interiorMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Styles moved to _global.scss;
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import ObjectView from '../../ui/components/layout/ObjectView.vue'
|
import SubobjectView from './SubobjectView.vue'
|
||||||
import LayoutDrag from './LayoutDrag'
|
import TelemetryView from './TelemetryView.vue'
|
||||||
|
import LayoutDrag from './../LayoutDrag'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
@ -148,13 +81,14 @@
|
|||||||
gridSize: Array
|
gridSize: Array
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
ObjectView
|
SubobjectView,
|
||||||
|
TelemetryView
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
classObject: function () {
|
classObject: function () {
|
||||||
return {
|
return {
|
||||||
'is-drilled-in': this.item.drilledIn,
|
'is-drilled-in': this.item.drilledIn,
|
||||||
'no-frame': !this.item.hasFrame
|
'no-frame': !this.item.config.hasFrame
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -164,7 +98,7 @@
|
|||||||
$event.stopPropagation();
|
$event.stopPropagation();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isBeingEdited(this.item.domainObject)) {
|
if (!this.openmct.editor.isEditing()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,10 +113,6 @@
|
|||||||
|
|
||||||
this.$emit('drilledIn', id);
|
this.$emit('drilledIn', id);
|
||||||
},
|
},
|
||||||
isBeingEdited(object) {
|
|
||||||
// TODO: add logic when inEditContext() is implemented in Vue.
|
|
||||||
return true;
|
|
||||||
},
|
|
||||||
updatePosition(event) {
|
updatePosition(event) {
|
||||||
let currentPosition = [event.pageX, event.pageY];
|
let currentPosition = [event.pageX, event.pageY];
|
||||||
this.initialPosition = this.initialPosition || currentPosition;
|
this.initialPosition = this.initialPosition || currentPosition;
|
||||||
@ -196,7 +126,7 @@
|
|||||||
|
|
||||||
this.updatePosition(event);
|
this.updatePosition(event);
|
||||||
this.activeDrag = new LayoutDrag(
|
this.activeDrag = new LayoutDrag(
|
||||||
this.item.rawPosition,
|
this.item.config.rawPosition,
|
||||||
posFactor,
|
posFactor,
|
||||||
dimFactor,
|
dimFactor,
|
||||||
this.gridSize
|
this.gridSize
|
||||||
@ -208,24 +138,31 @@
|
|||||||
this.updatePosition(event);
|
this.updatePosition(event);
|
||||||
|
|
||||||
if (this.activeDrag) {
|
if (this.activeDrag) {
|
||||||
this.$emit('dragInProgress', this.item.id, this.activeDrag.getAdjustedPosition(this.delta));
|
this.$emit(
|
||||||
|
'dragInProgress',
|
||||||
|
this.item,
|
||||||
|
this.activeDrag.getAdjustedPosition(this.delta)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
endDrag(event) {
|
endDrag(event) {
|
||||||
document.body.removeEventListener('mousemove', this.continueDrag);
|
document.body.removeEventListener('mousemove', this.continueDrag);
|
||||||
document.body.removeEventListener('mouseup', this.endDrag);
|
document.body.removeEventListener('mouseup', this.endDrag);
|
||||||
this.continueDrag(event);
|
this.continueDrag(event);
|
||||||
this.$emit('endDrag', this.item.id);
|
this.$emit('endDrag', this.item);
|
||||||
this.initialPosition = undefined;
|
this.initialPosition = undefined;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
let context = {
|
||||||
|
item: this.item.domainObject,
|
||||||
|
layoutItem: this.item
|
||||||
|
};
|
||||||
|
|
||||||
this.removeSelectable = this.openmct.selection.selectable(
|
this.removeSelectable = this.openmct.selection.selectable(
|
||||||
this.$el,
|
this.$el,
|
||||||
{
|
context,
|
||||||
item: this.item.domainObject
|
|
||||||
},
|
|
||||||
this.item.initSelect
|
this.item.initSelect
|
||||||
);
|
);
|
||||||
},
|
},
|
118
src/plugins/displayLayout/components/SubobjectView.vue
Normal file
118
src/plugins/displayLayout/components/SubobjectView.vue
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
<template>
|
||||||
|
<div class="u-contents">
|
||||||
|
<div class="c-so-view__header">
|
||||||
|
<div class="c-so-view__header__start">
|
||||||
|
<div class="c-so-view__name icon-object">{{ item.domainObject.name }}</div>
|
||||||
|
<div class="c-so-view__context-actions c-disclosure-button"></div>
|
||||||
|
</div>
|
||||||
|
<div class="c-so-view__header__end">
|
||||||
|
<div class="c-button icon-expand local-controls--hidden"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<object-view class="c-so-view__object-view"
|
||||||
|
:object="item.domainObject"></object-view>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
|
.c-so-view {
|
||||||
|
/*************************** HEADER */
|
||||||
|
&__header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
margin-bottom: $interiorMargin;
|
||||||
|
|
||||||
|
> [class*="__"] {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
> * + * {
|
||||||
|
margin-left: $interiorMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="__start"] {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="__end"] {
|
||||||
|
//justify-content: flex-end;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
|
||||||
|
[class*="button"] {
|
||||||
|
font-size: 0.7em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__name {
|
||||||
|
@include ellipsize();
|
||||||
|
flex: 0 1 auto;
|
||||||
|
font-size: 1.2em;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
// Object type icon
|
||||||
|
flex: 0 0 auto;
|
||||||
|
margin-right: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************** OBJECT VIEW */
|
||||||
|
&__object-view {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: auto;
|
||||||
|
|
||||||
|
.c-object-view {
|
||||||
|
.u-fills-container {
|
||||||
|
// Expand component types that fill a container
|
||||||
|
@include abs();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import ObjectView from '../../../ui/components/layout/ObjectView.vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
inject: ['openmct'],
|
||||||
|
props: {
|
||||||
|
item: Object
|
||||||
|
},
|
||||||
|
components: {
|
||||||
|
ObjectView,
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.item.config.attachListeners();
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
this.item.config.removeListeners();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
181
src/plugins/displayLayout/components/TelemetryView.vue
Normal file
181
src/plugins/displayLayout/components/TelemetryView.vue
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* Open MCT, Copyright (c) 2014-2018, 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="c-telemetry-view"
|
||||||
|
:style="styleObject">
|
||||||
|
<div v-if="showLabel"
|
||||||
|
class="c-telemetry-view__label">
|
||||||
|
<div class="c-telemetry-view__label-text">{{ item.domainObject.name }}</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div v-if="showValue"
|
||||||
|
class="c-telemetry-view__value"
|
||||||
|
:class="[telemetryClass]">
|
||||||
|
<div class="c-telemetry-view__value-text">{{ telemetryValue }}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '~styles/sass-base';
|
||||||
|
|
||||||
|
.c-telemetry-view {
|
||||||
|
display: flex;
|
||||||
|
align-items: stretch;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
// Label and value holders
|
||||||
|
flex: 1 1 auto;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
// justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
overflow: hidden;
|
||||||
|
padding: $interiorMargin;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
// Text elements
|
||||||
|
@include ellipsize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> * + * {
|
||||||
|
margin-left: $interiorMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-frame & {
|
||||||
|
@include abs();
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
inject: ['openmct'],
|
||||||
|
props: {
|
||||||
|
item: Object
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
showLabel() {
|
||||||
|
let displayMode = this.item.config.alphanumeric.displayMode;
|
||||||
|
return displayMode === 'all' || displayMode === 'label';
|
||||||
|
},
|
||||||
|
showValue() {
|
||||||
|
let displayMode = this.item.config.alphanumeric.displayMode;
|
||||||
|
return displayMode === 'all' || displayMode === 'value';
|
||||||
|
},
|
||||||
|
styleObject() {
|
||||||
|
let alphanumeric = this.item.config.alphanumeric;
|
||||||
|
return {
|
||||||
|
backgroundColor: alphanumeric.fill,
|
||||||
|
borderColor: alphanumeric.stroke,
|
||||||
|
color: alphanumeric.color,
|
||||||
|
fontSize: alphanumeric.size
|
||||||
|
}
|
||||||
|
},
|
||||||
|
valueMetadata() {
|
||||||
|
return this.metadata.value(this.item.config.alphanumeric.value);
|
||||||
|
},
|
||||||
|
valueFormatter() {
|
||||||
|
return this.formats[this.item.config.alphanumeric.value];
|
||||||
|
},
|
||||||
|
telemetryValue() {
|
||||||
|
if (!this.datum) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.valueFormatter && this.valueFormatter.format(this.datum);
|
||||||
|
},
|
||||||
|
telemetryClass() {
|
||||||
|
if (!this.datum) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let alarm = this.limitEvaluator && this.limitEvaluator.evaluate(this.datum, this.valueMetadata);
|
||||||
|
return alarm && alarm.cssClass;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
datum: {},
|
||||||
|
formats: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
requestHistoricalData() {
|
||||||
|
let bounds = this.openmct.time.bounds();
|
||||||
|
let options = {
|
||||||
|
start: bounds.start,
|
||||||
|
end: bounds.end,
|
||||||
|
size: 1
|
||||||
|
};
|
||||||
|
this.openmct.telemetry.request(this.item.domainObject, options)
|
||||||
|
.then(data => {
|
||||||
|
if (data.length > 0) {
|
||||||
|
this.updateView(data[data.length - 1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
subscribeToObject() {
|
||||||
|
this.subscription = this.openmct.telemetry.subscribe(this.item.domainObject, function (datum) {
|
||||||
|
if (this.openmct.time.clock() !== undefined) {
|
||||||
|
this.updateView(datum);
|
||||||
|
}
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
updateView(datum) {
|
||||||
|
this.datum = datum;
|
||||||
|
},
|
||||||
|
removeSubscription() {
|
||||||
|
if (this.subscription) {
|
||||||
|
this.subscription();
|
||||||
|
this.subscription = undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
refreshData(bounds, isTick) {
|
||||||
|
if (!isTick) {
|
||||||
|
this.datum = undefined;
|
||||||
|
this.requestHistoricalData(this.item.domainObject);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.limitEvaluator = this.openmct.telemetry.limitEvaluator(this.item.domainObject);
|
||||||
|
this.metadata = this.openmct.telemetry.getMetadata(this.item.domainObject);
|
||||||
|
this.formats = this.openmct.telemetry.getFormatMap(this.metadata);
|
||||||
|
|
||||||
|
this.requestHistoricalData();
|
||||||
|
this.subscribeToObject();
|
||||||
|
|
||||||
|
this.item.config.attachListeners();
|
||||||
|
this.openmct.time.on("bounds", this.refreshData);
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
this.removeSubscription();
|
||||||
|
this.item.config.removeListeners();
|
||||||
|
this.openmct.time.off("bounds", this.refreshData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
@ -20,10 +20,11 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
import Layout from './DisplayLayout.vue'
|
import Layout from './components/DisplayLayout.vue'
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import objectUtils from '../../api/objects/object-utils.js'
|
import objectUtils from '../../api/objects/object-utils.js'
|
||||||
import DisplayLayoutType from './DisplayLayoutType.js'
|
import DisplayLayoutType from './DisplayLayoutType.js'
|
||||||
|
import DisplayLayoutToolbar from './DisplayLayoutToolbar.js'
|
||||||
|
|
||||||
export default function () {
|
export default function () {
|
||||||
return function (openmct) {
|
return function (openmct) {
|
||||||
@ -63,6 +64,7 @@ export default function () {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
openmct.types.addType('layout', DisplayLayoutType());
|
openmct.types.addType('layout', DisplayLayoutType());
|
||||||
|
openmct.toolbars.addProvider(new DisplayLayoutToolbar(openmct));
|
||||||
openmct.composition.addPolicy((parent, child) => {
|
openmct.composition.addPolicy((parent, child) => {
|
||||||
if (parent.type === 'layout' && child.type === 'folder') {
|
if (parent.type === 'layout' && child.type === 'folder') {
|
||||||
return false;
|
return false;
|
||||||
@ -70,41 +72,5 @@ export default function () {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
openmct.toolbars.addProvider({
|
|
||||||
name: "Display Layout Toolbar",
|
|
||||||
key: "layout",
|
|
||||||
description: "A toolbar for objects inside a display layout.",
|
|
||||||
forSelection: function (selection) {
|
|
||||||
// Apply the layout toolbar if the selected object is inside a layout,
|
|
||||||
// and in edit mode.
|
|
||||||
return (selection &&
|
|
||||||
selection[1] &&
|
|
||||||
selection[1].context.item &&
|
|
||||||
selection[1].context.item.type === 'layout' &&
|
|
||||||
openmct.editor.isEditing());
|
|
||||||
},
|
|
||||||
toolbar: function (selection) {
|
|
||||||
let id = openmct.objects.makeKeyString(selection[0].context.item.identifier);
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
control: "toggle-button",
|
|
||||||
domainObject: selection[1].context.item,
|
|
||||||
property: "configuration.layout.panels[" + id + "].hasFrame",
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
value: false,
|
|
||||||
icon: 'icon-frame-hide',
|
|
||||||
title: "Hide frame"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: true,
|
|
||||||
icon: 'icon-frame-show',
|
|
||||||
title: "Show frame"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ $browseShdwSelectableHov: rgba($colorBodyFg, 0.2) 0 0 3px;
|
|||||||
$browseBorderSelected: 1px solid rgba($colorBodyFg, 0.6);
|
$browseBorderSelected: 1px solid rgba($colorBodyFg, 0.6);
|
||||||
$editBorderSelectable: 1px dotted rgba($editColor, 1);
|
$editBorderSelectable: 1px dotted rgba($editColor, 1);
|
||||||
$editBorderSelectableHov: 1px dashed rgba($editColor, 1);
|
$editBorderSelectableHov: 1px dashed rgba($editColor, 1);
|
||||||
$editBorderSelected: 1px solid $editColor;
|
$editBorderSelected: 1px solid rgba($editColor, 0.7);
|
||||||
$editBorderDrilledIn: 1px dashed #ff4d9a;
|
$editBorderDrilledIn: 1px dashed #ff4d9a;
|
||||||
$colorGridLines: rgba($editColor, 0.2);
|
$colorGridLines: rgba($editColor, 0.2);
|
||||||
|
|
||||||
|
@ -386,8 +386,24 @@ input[type=number]::-webkit-outer-spin-button {
|
|||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin cToolbarSeparator() {
|
||||||
|
$m: $interiorMargin;
|
||||||
|
$b: 1px;
|
||||||
|
display: block;
|
||||||
|
width: $m + $b; // Allow for border
|
||||||
|
border-right: $b solid $colorInteriorBorder;
|
||||||
|
margin-right: $m;
|
||||||
|
}
|
||||||
|
|
||||||
.c-toolbar {
|
.c-toolbar {
|
||||||
height: 24px; // Need to standardize the height
|
$p: $interiorMargin;
|
||||||
|
border-top: 1px solid $colorInteriorBorder;
|
||||||
|
height: $p + 24px; // Need to standardize the height
|
||||||
|
padding-top: $p;
|
||||||
|
|
||||||
|
&__separator {
|
||||||
|
@include cToolbarSeparator();
|
||||||
|
}
|
||||||
|
|
||||||
.c-click-icon {
|
.c-click-icon {
|
||||||
@include cControl();
|
@include cControl();
|
||||||
@ -444,14 +460,9 @@ input[type=number]::-webkit-outer-spin-button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
+ .c-button-set {
|
+ .c-button-set {
|
||||||
$m: $interiorMargin;
|
|
||||||
$b: 1px;
|
|
||||||
&:before {
|
&:before {
|
||||||
|
@include cToolbarSeparator();
|
||||||
content: '';
|
content: '';
|
||||||
display: block;
|
|
||||||
width: $m + $b; // Allow for border
|
|
||||||
border-right: $b solid $colorInteriorBorder;
|
|
||||||
margin-right: $m;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
.c-object-view {
|
|
||||||
display: contents;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import _ from "lodash"
|
import _ from "lodash"
|
||||||
|
|
||||||
@ -53,7 +47,7 @@ export default {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.viewContainer = document.createElement('div');
|
this.viewContainer = document.createElement('div');
|
||||||
this.viewContainer.classList.add('c-object-view');
|
this.viewContainer.classList.add('c-object-view','u-contents');
|
||||||
this.$el.append(this.viewContainer);
|
this.$el.append(this.viewContainer);
|
||||||
let provider = this.openmct.objectViews.getByProviderKey(this.viewKey);
|
let provider = this.openmct.objectViews.getByProviderKey(this.viewKey);
|
||||||
if (!provider) {
|
if (!provider) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="c-toolbar" v-if="structure.length !== 0">
|
<div class="c-toolbar">
|
||||||
<component v-for="item in structure"
|
<component v-for="item in structure"
|
||||||
:is="item.control"
|
:is="item.control"
|
||||||
:options="item"
|
:options="item"
|
||||||
@ -48,9 +48,14 @@
|
|||||||
let structure = this.openmct.toolbars.get(selection) || [];
|
let structure = this.openmct.toolbars.get(selection) || [];
|
||||||
this.structure = structure.map(function (item) {
|
this.structure = structure.map(function (item) {
|
||||||
let toolbarItem = {...item};
|
let toolbarItem = {...item};
|
||||||
|
let domainObject = toolbarItem.domainObject;
|
||||||
toolbarItem.control = "toolbar-" + toolbarItem.control;
|
toolbarItem.control = "toolbar-" + toolbarItem.control;
|
||||||
toolbarItem.value = _.get(toolbarItem.domainObject, item.property);
|
|
||||||
this.registerListener(toolbarItem.domainObject);
|
if (domainObject) {
|
||||||
|
toolbarItem.value = _.get(domainObject, item.property);
|
||||||
|
this.registerListener(domainObject);
|
||||||
|
}
|
||||||
|
|
||||||
return toolbarItem;
|
return toolbarItem;
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
@ -82,7 +87,10 @@
|
|||||||
updateToolbarAfterMutation() {
|
updateToolbarAfterMutation() {
|
||||||
this.structure = this.structure.map((item) => {
|
this.structure = this.structure.map((item) => {
|
||||||
let toolbarItem = {...item};
|
let toolbarItem = {...item};
|
||||||
let id = this.openmct.objects.makeKeyString(toolbarItem.domainObject.identifier);
|
let domainObject = toolbarItem.domainObject;
|
||||||
|
|
||||||
|
if (domainObject) {
|
||||||
|
let id = this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||||
let newObject = this.domainObjectsById[id].newObject;
|
let newObject = this.domainObjectsById[id].newObject;
|
||||||
|
|
||||||
if (newObject) {
|
if (newObject) {
|
||||||
@ -93,6 +101,7 @@
|
|||||||
toolbarItem.value = newValue;
|
toolbarItem.value = newValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return toolbarItem;
|
return toolbarItem;
|
||||||
});
|
});
|
||||||
@ -117,11 +126,15 @@
|
|||||||
let changedItemId = this.openmct.objects.makeKeyString(item.domainObject.identifier);
|
let changedItemId = this.openmct.objects.makeKeyString(item.domainObject.identifier);
|
||||||
this.structure = this.structure.map((s) => {
|
this.structure = this.structure.map((s) => {
|
||||||
let toolbarItem = {...s};
|
let toolbarItem = {...s};
|
||||||
let id = this.openmct.objects.makeKeyString(toolbarItem.domainObject.identifier);
|
let domainObject = toolbarItem.domainObject;
|
||||||
|
|
||||||
|
if (domainObject) {
|
||||||
|
let id = this.openmct.objects.makeKeyString(domainObject.identifier);
|
||||||
|
|
||||||
if (changedItemId === id && item.property === s.property) {
|
if (changedItemId === id && item.property === s.property) {
|
||||||
toolbarItem.value = value;
|
toolbarItem.value = value;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return toolbarItem;
|
return toolbarItem;
|
||||||
});
|
});
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
v-if="!this.options.preventNone"
|
v-if="!this.options.preventNone"
|
||||||
@click="select({value: 'transparent'})">
|
@click="select({value: 'transparent'})">
|
||||||
<div class="c-palette__item"></div>
|
<div class="c-palette__item"></div>
|
||||||
No fill
|
None
|
||||||
</div>
|
</div>
|
||||||
<div class="c-palette__items">
|
<div class="c-palette__items">
|
||||||
<div class="c-palette__item"
|
<div class="c-palette__item"
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div class="c-toolbar__separator"></div>
|
||||||
<div class="c-button-set"></div>
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
@ -27,7 +27,7 @@ const webpackConfig = {
|
|||||||
"bourbon": "bourbon.scss",
|
"bourbon": "bourbon.scss",
|
||||||
"espresso": path.join(__dirname, "src/styles/theme-espresso.scss"),
|
"espresso": path.join(__dirname, "src/styles/theme-espresso.scss"),
|
||||||
"snow": path.join(__dirname, "src/styles/theme-snow.scss"),
|
"snow": path.join(__dirname, "src/styles/theme-snow.scss"),
|
||||||
"vue": path.join(__dirname, "node_modules/vue/dist/vue.min.js"),
|
"vue": path.join(__dirname, "node_modules/vue/dist/vue.js"),
|
||||||
"d3-scale": path.join(__dirname, "node_modules/d3-scale/build/d3-scale.min.js"),
|
"d3-scale": path.join(__dirname, "node_modules/d3-scale/build/d3-scale.min.js"),
|
||||||
"styles": path.join(__dirname, "src/styles-new")
|
"styles": path.join(__dirname, "src/styles-new")
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user