From e07cfc9394106c397294b4d6a333dbfb2c2cc73f Mon Sep 17 00:00:00 2001 From: Pegah Sarram Date: Tue, 4 Dec 2018 09:12:45 -0800 Subject: [PATCH] Layout drawing (#2232) * - Show "Add" button in the toolbar when a display layout object is selected. - Add a flag to object view's show() method to indicate immediate selection of the view. If the view implements getSelectionContext() use it, otherwise set to default context. * Create a component for each element. * Saving work * Add element factory for creating new instances of elements. * Mutate element when a new one added and get elements when the component is mounted. * Add create() method for creating a new telemetry and element in their respective view configuration. * Add some of the toolbar controls for box, text, image and line elements. Also, add X, Y, Width and Height controls for alhpanumeric elements. * Pass name to addElement as type. * Add c-frame-inspectable class if item is inspectable. * Clean up * Hide frame for summary widgets by default. * Better styling for editing - s-selected on shell__main-container; - Better edit grid coloring for espresso; * - Update toolbar-button to support dialogs. - Update toolbar to construct a value object based on form keys if a toolbar item has a dialogi, and mutate the form keys. - Add toolbar controls for editing text and url for 'Text' and 'Image' elements respectively. * Editing-related changes - Removed hard-coded .is-selectable and .is-moveable from LayoutItem.vue, updates accordingly to _global.scss; - Theme constants updated; - TODO: apply changes to Flexible Layouts; * Better defaults - Better default grid size and object size; * - Fix toolbar-input to read value as a number if type is 'number'. - Remove rawPosition from view configuration and instead get the position and dimensions from the properties (x, y, width and height) directly. - Set the style property on the view configuration instead of the layout item. - Move the logic for updating the style to the view configuration. * Fix default dimensions for telemetry items and subobjects since the default grid size is changed. * Remove form definition for display layout type. * Reword the comment * Let subobject view configuration handle new panel creation. * Add default grid size back and remove unused code. * Pass in only the needed method. * Define default position in case the object is not added via drag 'n drop. --- platform/features/fixed/plugin.js | 6 +- .../displayLayout/DisplayLayoutToolbar.js | 340 +++++++++++++----- .../displayLayout/DisplayLayoutType.js | 3 +- .../displayLayout/ElementViewConfiguration.js | 171 +++++++++ .../SubobjectViewConfiguration.js | 80 ++++- .../TelemetryViewConfiguration.js | 68 +++- .../displayLayout/ViewConfiguration.js | 59 ++- .../displayLayout/components/BoxView.vue | 63 ++++ .../components/DisplayLayout.vue | 166 +++------ .../displayLayout/components/ImageView.vue | 65 ++++ .../displayLayout/components/LayoutItem.vue | 31 +- .../displayLayout/components/LineView.vue | 56 +++ .../displayLayout/components/TextView.vue | 67 ++++ src/plugins/displayLayout/plugin.js | 8 +- src/styles-new/_constants-espresso.scss | 7 +- src/styles-new/_constants-snow.scss | 6 +- src/styles-new/_global.scss | 14 +- src/ui/components/inspector/Elements.vue | 11 +- src/ui/components/layout/ObjectView.vue | 22 +- src/ui/components/toolbar/Toolbar.vue | 52 ++- .../toolbar/components/toolbar-button.vue | 7 +- .../toolbar/components/toolbar-input.vue | 8 +- src/ui/registries/ViewRegistry.js | 10 + src/ui/router/Browse.js | 15 +- 24 files changed, 1072 insertions(+), 263 deletions(-) create mode 100644 src/plugins/displayLayout/ElementViewConfiguration.js create mode 100644 src/plugins/displayLayout/components/BoxView.vue create mode 100644 src/plugins/displayLayout/components/ImageView.vue create mode 100644 src/plugins/displayLayout/components/LineView.vue create mode 100644 src/plugins/displayLayout/components/TextView.vue diff --git a/platform/features/fixed/plugin.js b/platform/features/fixed/plugin.js index 1e6c652285..c2601283ba 100644 --- a/platform/features/fixed/plugin.js +++ b/platform/features/fixed/plugin.js @@ -104,9 +104,9 @@ define([ } return (openmct.editor.isEditing() && - (selection[0] && selection[0].context.elementProxy && - selection[1] && selection[1].context.item.type === 'telemetry.fixed' || - selection[0] && selection[0].context.item.type === 'telemetry.fixed')); + selection[0] && selection[0].context.elementProxy && + ((selection[1] && selection[1].context.item.type === 'telemetry.fixed') || + (selection[0] && selection[0].context.item && selection[0].context.item.type === 'telemetry.fixed'))); }, toolbar: function (selection) { var imageProperties = ["add", "remove", "order", "stroke", "useGrid", "x", "y", "height", "width", "url"]; diff --git a/src/plugins/displayLayout/DisplayLayoutToolbar.js b/src/plugins/displayLayout/DisplayLayoutToolbar.js index 1df3a42377..5f758532a7 100644 --- a/src/plugins/displayLayout/DisplayLayoutToolbar.js +++ b/src/plugins/displayLayout/DisplayLayoutToolbar.js @@ -28,91 +28,116 @@ define([], function () { 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()); + // Apply the layout toolbar if the edit mode is on, and the selected object + // is inside a layout, or the main layout is selected. + return (openmct.editor.isEditing() && selection && + ((selection[1] && selection[1].context.item && selection[1].context.item.type === 'layout') || + (selection[0].context.item && selection[0].context.item.type === 'layout'))); }, toolbar: function (selection) { - let domainObject = selection[1].context.item; - let layoutItem = selection[0].context.layoutItem; + let selectedParent = selection[1] && selection[1].context.item, + selectedObject = selection[0].context.item, + layoutItem = selection[0].context.layoutItem, + toolbar = []; - if (layoutItem && layoutItem.type === 'telemetry-view') { - let path = "configuration.alphanumerics[" + layoutItem.config.alphanumeric.index + "]"; - let metadata = openmct.telemetry.getMetadata(layoutItem.domainObject); + if (selectedObject && selectedObject.type === 'layout') { + toolbar.push({ + control: "menu", + domainObject: selectedObject, + method: function (option) { + selection[0].context.addElement(option.name.toLowerCase()); + }, + key: "add", + icon: "icon-plus", + label: "Add", + options: [ + { + "name": "Box", + "class": "icon-box-round-corners" + }, + { + "name": "Line", + "class": "icon-line-horz" + }, + { + "name": "Text", + "class": "icon-font" + }, + { + "name": "Image", + "class": "icon-image" + } + ] + }); + } + + if (!layoutItem) { + return toolbar; + } + + if (layoutItem.type === 'subobject-view') { + if (toolbar.length > 0) { + toolbar.push({ + control: "separator" + }); + } + toolbar.push({ + control: "toggle-button", + domainObject: selectedParent, + 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" + } + ] + }); + } else { const TEXT_SIZE = [9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96]; + let path; + // TODO: get the path from the view configuration + // let path = layoutItem.config.path(); + if (layoutItem.type === 'telemetry-view') { + path = "configuration.alphanumerics[" + layoutItem.config.alphanumeric.index + "]"; + } else { + path = "configuration.elements[" + layoutItem.config.element.index + "]"; + } - 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" - } - ] - }, - { + let separator = { 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" - }, - { + fill = { control: "color-picker", - domainObject: domainObject, + domainObject: selectedParent, property: path + ".fill", icon: "icon-paint-bucket", title: "Set fill color" }, - { + stroke = { control: "color-picker", - domainObject: domainObject, + domainObject: selectedParent, property: path + ".stroke", icon: "icon-line-horz", title: "Set border color" }, - { + color = { control: "color-picker", - domainObject: domainObject, + domainObject: selectedParent, property: path + ".color", icon: "icon-font", mandatory: true, title: "Set text color", preventNone: true }, - { - control: "separator" - }, - { + size = { control: "select-menu", - domainObject: domainObject, + domainObject: selectedParent, property: path + ".size", title: "Set text size", options: TEXT_SIZE.map(size => { @@ -121,28 +146,181 @@ define([], function () { }; }) }, - ]; - } 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" - } - ] - } - ]; + x = { + control: "input", + type: "number", + domainObject: selectedParent, + property: path + ".x", + label: "X:", + title: "X position" + }, + y = { + control: "input", + type: "number", + domainObject: selectedParent, + property: path + ".y", + label: "Y:", + title: "Y position", + }, + width = { + control: 'input', + type: 'number', + domainObject: selectedParent, + property: path + ".width", + label: 'W:', + title: 'Resize object width' + }, + height = { + control: 'input', + type: 'number', + domainObject: selectedParent, + property: path + ".height", + label: 'H:', + title: 'Resize object height' + }; + + if (layoutItem.type === 'telemetry-view') { + // TODO: add "remove", "order", "useGrid" + let metadata = openmct.telemetry.getMetadata(layoutItem.domainObject), + displayMode = { + control: "select-menu", + domainObject: selectedParent, + property: path + ".displayMode", + title: "Set display mode", + options: [ + { + name: 'Label + Value', + value: 'all' + }, + { + name: "Label only", + value: "label" + }, + { + name: "Value only", + value: "value" + } + ] + }, + value = { + control: "select-menu", + domainObject: selectedParent, + property: path + ".value", + title: "Set value", + options: metadata.values().map(value => { + return { + name: value.name, + value: value.key + } + }) + }; + toolbar = [ + displayMode, + separator, + value, + separator, + fill, + stroke, + color, + separator, + size, + separator, + x, + y, + height, + width + ]; + } else if (layoutItem.type === 'text-view' ) { + // TODO: Add "remove", "order", "useGrid" + let text = { + control: "button", + domainObject: selectedParent, + property: path, + icon: "icon-gear", + title: "Edit text properties", + dialog: { + name: "Text Element Properties", + sections: [ + { + rows: [ + { + key: "text", + control: "textfield", + name: "Text", + required: true + } + ] + } + ] + } + }; + toolbar = [ + fill, + stroke, + color, + separator, + size, + separator, + x, + y, + height, + width, + separator, + text + ]; + } else if (layoutItem.type === 'box-view') { + // TODO: Add "remove", "order", "useGrid" + toolbar = [ + fill, + stroke, + separator, + x, + y, + height, + width + ]; + } else if (layoutItem.type === 'image-view') { + // TODO: Add "remove", "order", "useGrid" + let url = { + control: "button", + domainObject: selectedParent, + property: path, + icon: "icon-image", + title: "Edit image properties", + dialog: { + name: "Image Properties", + sections: [ + { + rows: [ + { + key: "url", + control: "textfield", + name: "Image URL", + "cssClass": "l-input-lg", + required: true + } + ] + } + ] + } + }; + toolbar = [ + stroke, + separator, + x, + y, + height, + width, + separator, + url + ]; + } else if (layoutItem.type === 'line-view') { + // TODO: Add "remove", "order", "useGrid", "x1", "y1", x2", "y2" + toolbar = [stroke]; + } } + + return toolbar; } } } diff --git a/src/plugins/displayLayout/DisplayLayoutType.js b/src/plugins/displayLayout/DisplayLayoutType.js index a21ce0cce3..3951ea9e82 100644 --- a/src/plugins/displayLayout/DisplayLayoutType.js +++ b/src/plugins/displayLayout/DisplayLayoutType.js @@ -30,7 +30,8 @@ define(function () { domainObject.composition = []; domainObject.configuration = { panels: {}, - alphanumerics: [] + alphanumerics: [], + elements: [] }; } } diff --git a/src/plugins/displayLayout/ElementViewConfiguration.js b/src/plugins/displayLayout/ElementViewConfiguration.js new file mode 100644 index 0000000000..3e4cfceb79 --- /dev/null +++ b/src/plugins/displayLayout/ElementViewConfiguration.js @@ -0,0 +1,171 @@ +/***************************************************************************** + * 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( + ['./ViewConfiguration'], + function (ViewConfiguration) { + class ElementViewConfiguration extends ViewConfiguration { + + static create(type, openmct) { + const DEFAULT_WIDTH = 10, + DEFAULT_HEIGHT = 5, + DEFAULT_X = 1, + DEFAULT_Y = 1; + const INITIAL_STATES = { + "image": { + stroke: "transparent" + }, + "box": { + fill: "#717171", + stroke: "transparent" + }, + "line": { + x: 5, + y: 3, + x2: 6, + y2: 6, + stroke: "#717171" + }, + "text": { + fill: "transparent", + stroke: "transparent", + size: "13px", + color: "" + } + }; + const DIALOGS = { + "image": { + name: "Image Properties", + sections: [ + { + rows: [ + { + key: "url", + control: "textfield", + name: "Image URL", + "cssClass": "l-input-lg", + required: true + } + ] + } + ] + }, + "text": { + name: "Text Element Properties", + sections: [ + { + rows: [ + { + key: "text", + control: "textfield", + name: "Text", + required: true + } + ] + } + ] + } + }; + + let element = INITIAL_STATES[type] || {}; + element = JSON.parse(JSON.stringify(element)); + element.x = element.x || DEFAULT_X; + element.y = element.y || DEFAULT_Y; + element.width = DEFAULT_WIDTH; + element.height = DEFAULT_HEIGHT; + element.type = type; + + return DIALOGS[type] ? + openmct.$injector.get('dialogService').getUserInput(DIALOGS[type], element) : + element; + } + + /** + * @param {Object} configuration the element (line, box, text or image) view configuration + * @param {Object} configuration.element + * @param {Object} configuration.domainObject the telemetry domain object + * @param {Object} configuration.openmct the openmct object + */ + constructor({element, ...rest}) { + super(rest); + this.element = element; + this.updateStyle(this.position()); + } + + path() { + return "configuration.elements[" + this.element.index + "]"; + } + + x() { + return this.element.x; + } + + y() { + return this.element.y; + } + + width() { + return this.element.width; + } + + height() { + return this.element.height; + } + + observeProperties() { + [ + "width", + "height", + "stroke", + "fill", + "x", + "y", + "x1", + "y1", + "x2", + "y2", + "color", + "size", + "text", + "url" + ].forEach(property => { + this.attachListener(property, newValue => { + this.element[property] = newValue; + + if (property === 'width' || property === 'height' || + property === 'x' || property === 'y') { + this.updateStyle(); + } + }); + }); + + // TODO: attach listener for useGrid + } + + inspectable() { + return false; + } + } + + return ElementViewConfiguration; + } +); diff --git a/src/plugins/displayLayout/SubobjectViewConfiguration.js b/src/plugins/displayLayout/SubobjectViewConfiguration.js index 5839bf7f15..67352ce6f9 100644 --- a/src/plugins/displayLayout/SubobjectViewConfiguration.js +++ b/src/plugins/displayLayout/SubobjectViewConfiguration.js @@ -25,28 +25,94 @@ define( function (ViewConfiguration) { class SubobjectViewConfiguration extends ViewConfiguration { + static create(domainObject, gridSize, position) { + const MINIMUM_FRAME_SIZE = [320, 180], + DEFAULT_DIMENSIONS = [10, 10], + DEFAULT_POSITION = [0, 0], + DEFAULT_HIDDEN_FRAME_TYPES = ['hyperlink', 'summary-widget']; + + function getDefaultDimensions() { + return MINIMUM_FRAME_SIZE.map((min, index) => { + return Math.max( + Math.ceil(min / gridSize[index]), + DEFAULT_DIMENSIONS[index] + ); + }); + } + + function hasFrameByDefault(type) { + return DEFAULT_HIDDEN_FRAME_TYPES.indexOf(type) === -1; + } + + position = position || DEFAULT_POSITION; + let defaultDimensions = getDefaultDimensions(); + let panel = { + width: defaultDimensions[0], + height: defaultDimensions[1], + x: position[0], + y: position[1], + hasFrame: hasFrameByDefault(domainObject.type) + }; + + return panel; + } + /** * * @param {Object} configuration the subobject view configuration * @param {String} configuration.id the domain object keystring identifier - * @param {Boolean} configuration.hasFrame flag to show/hide the frame - * @param {Object} configuration.domainObject the domain object - * @param {Object} configuration.rawPosition an object that holds raw position and dimensions + * @param {Boolean} configuration.panel + * @param {Object} configuration.domainObject the domain object to observe the changes on * @param {Object} configuration.openmct the openmct object */ - constructor({id, hasFrame, ...rest}) { + constructor({panel, id, ...rest}) { super(rest); this.id = id; - this.hasFrame = hasFrame; + this.panel = panel; + this.hasFrame = this.hasFrame.bind(this); + this.updateStyle(this.position()); } path() { return "configuration.panels[" + this.id + "]"; } + x() { + return this.panel.x; + } + + y() { + return this.panel.y; + } + + width() { + return this.panel.width; + } + + height() { + return this.panel.height; + } + + hasFrame() { + return this.panel.hasFrame; + } + observeProperties() { - this.attachListener("hasFrame", newValue => { - this.hasFrame = newValue; + [ + 'hasFrame', + 'x', + 'y', + 'width', + 'height' + ].forEach(property => { + this.attachListener(property, newValue => { + this.panel[property] = newValue; + + if (property === 'width' || property === 'height' || + property === 'x' || property === 'y') { + this.updateStyle(); + } + }); }); } } diff --git a/src/plugins/displayLayout/TelemetryViewConfiguration.js b/src/plugins/displayLayout/TelemetryViewConfiguration.js index 71693f5141..1a22933b9d 100644 --- a/src/plugins/displayLayout/TelemetryViewConfiguration.js +++ b/src/plugins/displayLayout/TelemetryViewConfiguration.js @@ -23,24 +23,77 @@ define( ['./ViewConfiguration'], function (ViewConfiguration) { + class TelemetryViewConfiguration extends ViewConfiguration { + static create(domainObject, position, openmct) { + const DEFAULT_TELEMETRY_DIMENSIONS = [10, 5]; + + function getDefaultTelemetryValue(domainObject, openmct) { + let metadata = 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; + } + + let alphanumeric = { + identifier: domainObject.identifier, + x: position[0], + y: position[1], + width: DEFAULT_TELEMETRY_DIMENSIONS[0], + height: DEFAULT_TELEMETRY_DIMENSIONS[1], + displayMode: 'all', + value: getDefaultTelemetryValue(domainObject, openmct), + stroke: "transparent", + fill: "", + color: "", + size: "13px", + }; + + return alphanumeric; + } /** * @param {Object} configuration the telemetry object view configuration * @param {Object} configuration.alphanumeric - * @param {Object} configuration.domainObject the telemetry domain object - * @param {Object} configuration.rawPosition an object that holds raw position and dimensions + * @param {Object} configuration.domainObject the domain object to observe the changes on * @param {Object} configuration.openmct the openmct object */ constructor({alphanumeric, ...rest}) { super(rest); this.alphanumeric = alphanumeric; + this.updateStyle(this.position()); } path() { return "configuration.alphanumerics[" + this.alphanumeric.index + "]"; } + x() { + return this.alphanumeric.x; + } + + y() { + return this.alphanumeric.y; + } + + width() { + return this.alphanumeric.width; + } + + height() { + return this.alphanumeric.height; + } + observeProperties() { [ 'displayMode', @@ -48,10 +101,19 @@ define( 'fill', 'stroke', 'color', - 'size' + 'size', + 'x', + 'y', + 'width', + 'height' ].forEach(property => { this.attachListener(property, newValue => { this.alphanumeric[property] = newValue; + + if (property === 'width' || property === 'height' || + property === 'x' || property === 'y') { + this.updateStyle(); + } }); }); } diff --git a/src/plugins/displayLayout/ViewConfiguration.js b/src/plugins/displayLayout/ViewConfiguration.js index f7f4db8ce7..37a4387b9c 100644 --- a/src/plugins/displayLayout/ViewConfiguration.js +++ b/src/plugins/displayLayout/ViewConfiguration.js @@ -24,20 +24,23 @@ function () { class ViewConfiguration { - constructor({domainObject, openmct, rawPosition}) { + constructor({domainObject, openmct, gridSize}) { this.domainObject = domainObject; - this.rawPosition = rawPosition; + this.gridSize = gridSize; this.mutatePosition = this.mutatePosition.bind(this); this.listeners = []; this.observe = openmct.objects.observe.bind(openmct.objects); this.mutate = function (path, value) { openmct.objects.mutate(this.domainObject, path, value); }.bind(this); + this.newPosition = {}; } mutatePosition() { - this.mutate(this.path() + ".dimensions", this.rawPosition.dimensions); - this.mutate(this.path() + ".position", this.rawPosition.position); + this.mutate(this.path() + ".x", this.newPosition.position[0]); + this.mutate(this.path() + ".y", this.newPosition.position[1]); + this.mutate(this.path() + ".width", this.newPosition.dimensions[0]); + this.mutate(this.path() + ".height", this.newPosition.dimensions[1]); } attachListener(property, callback) { @@ -58,13 +61,59 @@ this.listeners = []; } - path() { + position() { + return { + position: [this.x(), this.y()], + dimensions: [this.width(), this.height()] + }; + } + + path() { throw "NOT IMPLEMENTED;" } + inspectable() { + return true; + } + + updateStyle(raw) { + if (!raw) { + raw = this.position(); + } + + this.style = { + 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' + }; + } + observeProperties() { // Not implemented } + + x() { + // Not implemented + } + + y() { + // Not implemented + } + + width() { + // Not implemented + } + + height() { + // Not implemented + } + + hasFrame() { + // Not implemented + } } return ViewConfiguration; diff --git a/src/plugins/displayLayout/components/BoxView.vue b/src/plugins/displayLayout/components/BoxView.vue new file mode 100644 index 0000000000..ca2d3a3cbb --- /dev/null +++ b/src/plugins/displayLayout/components/BoxView.vue @@ -0,0 +1,63 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ + + + + + + \ No newline at end of file diff --git a/src/plugins/displayLayout/components/DisplayLayout.vue b/src/plugins/displayLayout/components/DisplayLayout.vue index 0c11bd8faf..869a06e755 100644 --- a/src/plugins/displayLayout/components/DisplayLayout.vue +++ b/src/plugins/displayLayout/components/DisplayLayout.vue @@ -88,15 +88,9 @@ import LayoutItem from './LayoutItem.vue'; import TelemetryViewConfiguration from './../TelemetryViewConfiguration.js' import SubobjectViewConfiguration from './../SubobjectViewConfiguration.js' + import ElementViewConfiguration from './../ElementViewConfiguration.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' - ]; + const DEFAULT_GRID_SIZE = [10, 10]; export default { data() { @@ -119,25 +113,25 @@ this.makeTelemetryItem(alphanumeric, false); }); }, - makeFrameItem(panel, initSelect) { - let rawPosition = { - position: panel.position, - dimensions: panel.dimensions - }; - let style = this.convertPosition(rawPosition); + getElements() { + let elements = this.newDomainObject.configuration.elements || []; + elements.forEach((element, index) => { + element.index = index; + this.makeElementItem(element, false); + }); + }, + makeSubobjectItem(panel, initSelect) { let id = this.openmct.objects.makeKeyString(panel.domainObject.identifier); let config = new SubobjectViewConfiguration({ domainObject: this.newDomainObject, + panel: panel, id: id, - hasFrame: panel.hasFrame, - rawPosition: rawPosition, - openmct: openmct + openmct: openmct, + gridSize: this.gridSize }); - this.layoutItems.push({ id: id, domainObject: panel.domainObject, - style: style, drilledIn: this.isItemDrilledIn(id), initSelect: initSelect, type: 'subobject-view', @@ -145,60 +139,35 @@ }); }, 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({ domainObject: this.newDomainObject, alphanumeric: alphanumeric, - rawPosition: rawPosition, - openmct: openmct + openmct: openmct, + gridSize: this.gridSize }); - 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] - ); + makeElementItem(element, initSelect) { + let config = new ElementViewConfiguration({ + domainObject: this.newDomainObject, + element: element, + openmct: openmct, + gridSize: this.gridSize + }); + this.layoutItems.push({ + initSelect: initSelect, + type: element.type + '-view', + config: config }); - }, - 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) { @@ -219,9 +188,8 @@ return this.drilledIn === id; }, updatePosition(item, newPosition) { - let newStyle = this.convertPosition(newPosition); - item.config.rawPosition = newPosition; - item.style = newStyle; + item.config.newPosition = newPosition; + item.config.updateStyle(newPosition); }, bypassSelection($event) { if (this.dragInProgress) { @@ -236,7 +204,7 @@ setTimeout(function () { this.dragInProgress = false; }.bind(this), 0); - + // TODO: emit "finishResizing" for view components to mutate position? item.config.mutatePosition(); }, mutate(path, value) { @@ -278,39 +246,12 @@ } }, 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 || []; + let alphanumeric = TelemetryViewConfiguration.create(domainObject, position, this.openmct); 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(); }, @@ -322,7 +263,7 @@ return false; } }, - addObject(domainObject) { + addSubobject(domainObject) { if (!this.isTelemetry(domainObject)) { let panels = this.newDomainObject.configuration.panels, id = this.openmct.objects.makeKeyString(domainObject.identifier), @@ -330,35 +271,29 @@ mutateObject = false, initSelect = false; - // If this is a new panel, select it and save the configuration. + // If the panel doesn't exist, create one and mutate the configuration if (!panel) { - panel = {}; - mutateObject = true; + panel = SubobjectViewConfiguration.create(domainObject, this.gridSize, this.droppedObjectPosition); 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); + delete this.droppedObjectPosition; } panel.domainObject = domainObject; - this.makeFrameItem(panel, initSelect); + this.makeSubobjectItem(panel, initSelect); } }, - removeObject() { - + removeSubobject() { + // Not yet implemented + }, + addElement(type) { + let elements = this.newDomainObject.configuration.elements || []; + Promise.resolve(ElementViewConfiguration.create(type, this.openmct)) + .then(element => { + element.index = elements.push(element) - 1; + this.mutate("configuration.elements", elements); + this.makeElementItem(element, true); + }); } }, mounted() { @@ -373,15 +308,16 @@ 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.on('add', this.addSubobject); + this.composition.on('remove', this.removeSubobject); this.composition.load(); this.getAlphanumerics(); + this.getElements(); }, destroyed: function () { this.openmct.off('change', this.setSelection); - this.composition.off('add', this.addObject); - this.composition.off('remove', this.removeObject); + this.composition.off('add', this.addSubobject); + this.composition.off('remove', this.removeSubobject); this.unlisten(); } } diff --git a/src/plugins/displayLayout/components/ImageView.vue b/src/plugins/displayLayout/components/ImageView.vue new file mode 100644 index 0000000000..2d9ce9ac7d --- /dev/null +++ b/src/plugins/displayLayout/components/ImageView.vue @@ -0,0 +1,65 @@ +/***************************************************************************** + * 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. + *****************************************************************************/ + + + + + + \ No newline at end of file diff --git a/src/plugins/displayLayout/components/LayoutItem.vue b/src/plugins/displayLayout/components/LayoutItem.vue index b22cd7f6b6..4744455a07 100644 --- a/src/plugins/displayLayout/components/LayoutItem.vue +++ b/src/plugins/displayLayout/components/LayoutItem.vue @@ -21,12 +21,14 @@ *****************************************************************************/