mirror of
https://github.com/nasa/openmct.git
synced 2025-06-16 22:28:13 +00:00
Implement multi selection (#2351)
* Modify Selection API to support multi-select via shift click. * Add support for shift + click to add and remove the selection. * Display message in Location and Properties for multi-select. * Define applicableSelectedItems for toolbar items. Move toolbar control definitions to functions. * Hide positioning inputs if multi-select. Show a 'non-specific' icon when a discrete setting can't be shown in a mixed setting." * Add toolbar controls in groups per layout item type. Add nonSpecific property to toolbar items to be used by toolbar controls to show non-specific icon. * Modify toolbar button to react to nonSpecific flag. Get form value by checking value of applicable selected items. * Support deleting multiple selected objects. * Do not disable controls when selected items have mixed setting. * Revert default color to original value. * Changes to snap-to-grid * Remove timeout for updating toolbar after mutation. Do not copy toolbar item when iterating the structure. * Implement move to top and move to bottom for multi-select * Implement move up and move down for multi-select. * Markup and CSS changes for mixed settings in toolbar - Toggle, color-picker buttons; - TODO: check other themes and sync; * Mixed settings styling complete - Refined and synced theme constants; - Styling for all toolbar components; - Text size menu handling; - Inspector messaging; * Fix selection path * Mixed settings styling refinements - Normalized button styling for mixed style context; - Better theme constant naming; - Refined swatch styling, better theme constants; * First cut at getting the bounding rectangle working for multi-select. * Set pointer-events to none on c-edit-frame to prevent marquee reacting to click events. * Delete capturing before calling select. * Remove EditMarquee from ITEM_TYPE_VIEW_MAP * Pass selected layout items as a prop to edit marquee instead of selection so that x, y, w, h are updated. * Multi-select c-frame-edit visual fixes - WIP * Add complexContent class for a single selected item whose type is subobject-view. * Move 'c-frame-edit-move' div to layout frame. * Saving work - multi-move WIP * Fixes issue with selection happening at end of drag * Styles fixed for new markup organization - Marquee, frame styles; - $editMarqueeBorder style added to theme constants; * Significant functionality for .c-frame-edit__move element - Added .is-multi-selected class to .l-layout when > 1 items selected; - __move element now handles multi-select and complex content (CC) objects: -- 0 to 1 items selected, displays as hover bar with grippy on all CC objects, -- > 1 items selected, __move covers all of the frame of all selected CC items and doesn't allow sub-object selection, and only displays as hover bar on non-selected CC objects; - Added better styling for selected objects while editing; - Code cleanup and consolidation; - Left translucent green style applied to __move element to temporarily aid development; - TODO: fix line drawing object; * - Fix an issue where shift click did not remove the selected item from the selection after move. - Modify telemetry and subobject views to emit move and endMove events. - Clone selectedLayoutItems to get initial positions instead of selection so subsequent moves start from the current position. * Fix cursor for __move, code comment refinements * Code cleanup, line view markup changes - line view markup brought into line with structure in LayoutFrame.vue; * Implement multi-resize * Simplify edit marquee code. Revert image and text views' default position to the original values. * Fix resize for single selection when snap to grid is disabled * Hide edit marquee if single line is selected, and show c-frame-edit in line-view instead. * Fix for LineView handles * Remove snap to grid toggle button and modify the migration script to convert elements with pixel coordinates to grid. * Fix resizing single line * Calculate width and height differently for line to position marquee correctly. * Fix moving single selected line * Calculate the height and width for line before comparing them with max height and width to correct the marquee position. * Change the logic for showing frame edit for lines to check for item id. * Allow multi-move with line in the mix. * Implement multi-resize when grabbing SW corner. * Removed temp green tint from __move element * Fix object undefined error. * Implement multi-resize for all items except line (take 2). * Misc UI 7 - CSS selectors to properly display edit marquee, don't show in browse mode; * Fix multi-resize for lines. Make sure line's height and width is minimum 1. * Disable inspector views when multiple objects are selected. * Restored layout grid display on sub-layout selection * Clean up code * Fixes - Edit marquee display fixes; * More code clean up * SIGNIFICANT fixes and rewriting in LayoutFrame.vue - Styles for .c-frame-edit__move element for selection and hovering; - local controls; - view large button; - Theme constants updated; * Get selected item's index from layoutItems. * Address review feedback. * Merge topic-core-refactor * Reset keyString to empty string after setting original path when domainObject is undefined. Add proper check for selection.
This commit is contained in:
committed by
Deep Tailor
parent
964c326535
commit
c6053e234a
@ -25,14 +25,20 @@ define([
|
|||||||
cssClass: representation.cssClass,
|
cssClass: representation.cssClass,
|
||||||
description: representation.description,
|
description: representation.description,
|
||||||
canView: function (selection) {
|
canView: function (selection) {
|
||||||
if (!selection[0] || !selection[0].context.item) {
|
if (selection.length === 0 || selection[0].length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let domainObject = selection[0].context.item;
|
|
||||||
return domainObject.type === typeDefinition.key;
|
let selectionContext = selection[0][0].context;
|
||||||
|
|
||||||
|
if (!selectionContext.item) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return selectionContext.item.type === typeDefinition.key;
|
||||||
},
|
},
|
||||||
view: function (selection) {
|
view: function (selection) {
|
||||||
let domainObject = selection[0].context.item;
|
let domainObject = selection[0][0].context.item;
|
||||||
let $rootScope = openmct.$injector.get('$rootScope');
|
let $rootScope = openmct.$injector.get('$rootScope');
|
||||||
let templateLinker = openmct.$injector.get('templateLinker');
|
let templateLinker = openmct.$injector.get('templateLinker');
|
||||||
let scope = $rootScope.$new();
|
let scope = $rootScope.$new();
|
||||||
|
@ -28,11 +28,17 @@ define([], function () {
|
|||||||
key: "layout",
|
key: "layout",
|
||||||
description: "A toolbar for objects inside a display layout.",
|
description: "A toolbar for objects inside a display layout.",
|
||||||
forSelection: function (selection) {
|
forSelection: function (selection) {
|
||||||
// Apply the layout toolbar if the selected object
|
if (!selection || selection.length === 0) {
|
||||||
// is inside a layout, or the main layout is selected.
|
return false;
|
||||||
return (selection &&
|
}
|
||||||
((selection[1] && selection[1].context.item && selection[1].context.item.type === 'layout') ||
|
|
||||||
(selection[0].context.item && selection[0].context.item.type === 'layout')));
|
let selectionPath = selection[0];
|
||||||
|
let selectedObject = selectionPath[0];
|
||||||
|
let selectedParent = selectionPath[1];
|
||||||
|
|
||||||
|
// Apply the layout toolbar if the selected object is inside a layout, or the main layout is selected.
|
||||||
|
return (selectedParent && selectedParent.context.item && selectedParent.context.item.type === 'layout') ||
|
||||||
|
(selectedObject.context.item && selectedObject.context.item.type === 'layout');
|
||||||
},
|
},
|
||||||
toolbar: function (selection) {
|
toolbar: function (selection) {
|
||||||
const DIALOG_FORM = {
|
const DIALOG_FORM = {
|
||||||
@ -73,27 +79,36 @@ define([], function () {
|
|||||||
return openmct.$injector.get('dialogService').getUserInput(form, {});
|
return openmct.$injector.get('dialogService').getUserInput(form, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPath() {
|
function getPath(selectionPath) {
|
||||||
return `configuration.items[${selection[0].context.index}]`;
|
return `configuration.items[${selectionPath[0].context.index}]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
let selectedParent = selection[1] && selection[1].context.item,
|
function getAllTypes(selection) {
|
||||||
selectedObject = selection[0].context.item,
|
return selection.filter(selectionPath => {
|
||||||
layoutItem = selection[0].context.layoutItem,
|
let type = selectionPath[0].context.layoutItem.type;
|
||||||
toolbar = [];
|
return type === 'text-view' ||
|
||||||
|
type === 'telemetry-view' ||
|
||||||
|
type === 'box-view' ||
|
||||||
|
type === 'image-view' ||
|
||||||
|
type === 'line-view' ||
|
||||||
|
type === 'subobject-view';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (selectedObject && selectedObject.type === 'layout') {
|
function getAddButton(selection, selectionPath) {
|
||||||
toolbar.push({
|
if (selection.length === 1) {
|
||||||
|
selectionPath = selectionPath || selection[0];
|
||||||
|
return {
|
||||||
control: "menu",
|
control: "menu",
|
||||||
domainObject: selectedObject,
|
domainObject: selectionPath[0].context.item,
|
||||||
method: function (option) {
|
method: function (option) {
|
||||||
let name = option.name.toLowerCase();
|
let name = option.name.toLowerCase();
|
||||||
let form = DIALOG_FORM[name];
|
let form = DIALOG_FORM[name];
|
||||||
if (form) {
|
if (form) {
|
||||||
getUserInput(form)
|
getUserInput(form)
|
||||||
.then(element => selection[0].context.addElement(name, element));
|
.then(element => selectionPath[0].context.addElement(name, element));
|
||||||
} else {
|
} else {
|
||||||
selection[0].context.addElement(name);
|
selectionPath[0].context.addElement(name);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
key: "add",
|
key: "add",
|
||||||
@ -117,23 +132,43 @@ define([], function () {
|
|||||||
"class": "icon-image"
|
"class": "icon-image"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!layoutItem) {
|
|
||||||
return toolbar;
|
|
||||||
}
|
|
||||||
|
|
||||||
let separator = {
|
|
||||||
control: "separator"
|
|
||||||
};
|
};
|
||||||
let remove = {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getToggleFrameButton(selectedParent, selection) {
|
||||||
|
return {
|
||||||
|
control: "toggle-button",
|
||||||
|
domainObject: selectedParent,
|
||||||
|
applicableSelectedItems: selection.filter(selectionPath =>
|
||||||
|
selectionPath[0].context.layoutItem.type === 'subobject-view'
|
||||||
|
),
|
||||||
|
property: function (selectionPath) {
|
||||||
|
return getPath(selectionPath) + ".hasFrame";
|
||||||
|
},
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
value: false,
|
||||||
|
icon: 'icon-frame-show',
|
||||||
|
title: "Frame visible"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: true,
|
||||||
|
icon: 'icon-frame-hide',
|
||||||
|
title: "Frame hidden"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getRemoveButton(selectedParent, selectionPath, selection) {
|
||||||
|
return {
|
||||||
control: "button",
|
control: "button",
|
||||||
domainObject: selectedParent,
|
domainObject: selectedParent,
|
||||||
icon: "icon-trash",
|
icon: "icon-trash",
|
||||||
title: "Delete the selected object",
|
title: "Delete the selected object",
|
||||||
method: function () {
|
method: function () {
|
||||||
let removeItem = selection[1].context.removeItem;
|
let removeItem = selectionPath[1].context.removeItem;
|
||||||
let prompt = openmct.overlays.dialog({
|
let prompt = openmct.overlays.dialog({
|
||||||
iconClass: 'alert',
|
iconClass: 'alert',
|
||||||
message: `Warning! This action will remove this item from the Display Layout. Do you want to continue?`,
|
message: `Warning! This action will remove this item from the Display Layout. Do you want to continue?`,
|
||||||
@ -142,7 +177,7 @@ define([], function () {
|
|||||||
label: 'Ok',
|
label: 'Ok',
|
||||||
emphasis: 'true',
|
emphasis: 'true',
|
||||||
callback: function () {
|
callback: function () {
|
||||||
removeItem(layoutItem, selection[0].context.index);
|
removeItem(getAllTypes(selection));
|
||||||
prompt.dismiss();
|
prompt.dismiss();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -156,7 +191,10 @@ define([], function () {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let stackOrder = {
|
}
|
||||||
|
|
||||||
|
function getStackOrder(selectedParent, selectionPath) {
|
||||||
|
return {
|
||||||
control: "menu",
|
control: "menu",
|
||||||
domainObject: selectedParent,
|
domainObject: selectedParent,
|
||||||
icon: "icon-layers",
|
icon: "icon-layers",
|
||||||
@ -184,138 +222,122 @@ define([], function () {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
method: function (option) {
|
method: function (option) {
|
||||||
selection[1].context.orderItem(option.value, selection[0].context.index);
|
selectionPath[1].context.orderItem(option.value, getAllTypes(selection));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let useGrid = {
|
|
||||||
control: "toggle-button",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
property: function () {
|
|
||||||
return getPath() + ".useGrid";
|
|
||||||
},
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
value: false,
|
|
||||||
icon: "icon-grid-snap-to",
|
|
||||||
title: "Grid snapping enabled"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: true,
|
|
||||||
icon: "icon-grid-snap-no",
|
|
||||||
title: "Grid snapping disabled"
|
|
||||||
}
|
}
|
||||||
]
|
|
||||||
};
|
function getXInput(selectedParent, selection) {
|
||||||
let x = {
|
if (selection.length === 1) {
|
||||||
|
return {
|
||||||
control: "input",
|
control: "input",
|
||||||
type: "number",
|
type: "number",
|
||||||
domainObject: selectedParent,
|
domainObject: selectedParent,
|
||||||
property: function () {
|
applicableSelectedItems: getAllTypes(selection),
|
||||||
return getPath() + ".x";
|
property: function (selectionPath) {
|
||||||
|
return getPath(selectionPath) + ".x";
|
||||||
},
|
},
|
||||||
label: "X:",
|
label: "X:",
|
||||||
title: "X position"
|
title: "X position"
|
||||||
},
|
};
|
||||||
y = {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getYInput(selectedParent, selection) {
|
||||||
|
if (selection.length === 1) {
|
||||||
|
return {
|
||||||
control: "input",
|
control: "input",
|
||||||
type: "number",
|
type: "number",
|
||||||
domainObject: selectedParent,
|
domainObject: selectedParent,
|
||||||
property: function () {
|
applicableSelectedItems: getAllTypes(selection),
|
||||||
return getPath() + ".y";
|
property: function (selectionPath) {
|
||||||
|
return getPath(selectionPath) + ".y";
|
||||||
},
|
},
|
||||||
label: "Y:",
|
label: "Y:",
|
||||||
title: "Y position",
|
title: "Y position",
|
||||||
},
|
};
|
||||||
width = {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getWidthInput(selectedParent, selection) {
|
||||||
|
if (selection.length === 1) {
|
||||||
|
return {
|
||||||
control: 'input',
|
control: 'input',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
domainObject: selectedParent,
|
domainObject: selectedParent,
|
||||||
property: function () {
|
applicableSelectedItems: getAllTypes(selection),
|
||||||
return getPath() + ".width";
|
property: function (selectionPath) {
|
||||||
|
return getPath(selectionPath) + ".width";
|
||||||
},
|
},
|
||||||
label: 'W:',
|
label: 'W:',
|
||||||
title: 'Resize object width'
|
title: 'Resize object width'
|
||||||
},
|
};
|
||||||
height = {
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getHeightInput(selectedParent, selection) {
|
||||||
|
if (selection.length === 1) {
|
||||||
|
return {
|
||||||
control: 'input',
|
control: 'input',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
domainObject: selectedParent,
|
domainObject: selectedParent,
|
||||||
property: function () {
|
applicableSelectedItems: getAllTypes(selection),
|
||||||
return getPath() + ".height";
|
property: function (selectionPath) {
|
||||||
|
return getPath(selectionPath) + ".height";
|
||||||
},
|
},
|
||||||
label: 'H:',
|
label: 'H:',
|
||||||
title: 'Resize object height'
|
title: 'Resize object height'
|
||||||
};
|
};
|
||||||
|
}
|
||||||
if (layoutItem.type === 'subobject-view') {
|
|
||||||
if (toolbar.length > 0) {
|
|
||||||
toolbar.push(separator);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toolbar.push({
|
function getX2Input(selectedParent, selection) {
|
||||||
control: "toggle-button",
|
if (selection.length === 1) {
|
||||||
|
return {
|
||||||
|
control: "input",
|
||||||
|
type: "number",
|
||||||
domainObject: selectedParent,
|
domainObject: selectedParent,
|
||||||
property: function () {
|
applicableSelectedItems: selection.filter(selectionPath => {
|
||||||
return getPath() + ".hasFrame";
|
return selectionPath[0].context.layoutItem.type === 'line-view';
|
||||||
|
}),
|
||||||
|
property: function (selectionPath) {
|
||||||
|
return getPath(selectionPath) + ".x2";
|
||||||
},
|
},
|
||||||
options: [
|
label: "X2:",
|
||||||
{
|
title: "X2 position"
|
||||||
value: false,
|
};
|
||||||
icon: 'icon-frame-show',
|
|
||||||
title: "Frame visible"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
value: true,
|
|
||||||
icon: 'icon-frame-hide',
|
|
||||||
title: "Frame hidden"
|
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
});
|
|
||||||
toolbar.push(separator);
|
function getY2Input(selectedParent, selection) {
|
||||||
toolbar.push(stackOrder);
|
if (selection.length === 1) {
|
||||||
toolbar.push(x);
|
return {
|
||||||
toolbar.push(y);
|
control: "input",
|
||||||
toolbar.push(width);
|
type: "number",
|
||||||
toolbar.push(height);
|
domainObject: selectedParent,
|
||||||
toolbar.push(useGrid);
|
applicableSelectedItems: selection.filter(selectionPath => {
|
||||||
toolbar.push(separator);
|
return selectionPath[0].context.layoutItem.type === 'line-view';
|
||||||
toolbar.push(remove);
|
}),
|
||||||
} else {
|
property: function (selectionPath) {
|
||||||
|
return getPath(selectionPath) + ".y2";
|
||||||
|
},
|
||||||
|
label: "Y2:",
|
||||||
|
title: "Y2 position",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTextSizeMenu(selectedParent, selection) {
|
||||||
const TEXT_SIZE = [8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96, 128];
|
const TEXT_SIZE = [8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 30, 36, 48, 72, 96, 128];
|
||||||
let fill = {
|
return {
|
||||||
control: "color-picker",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
property: function () {
|
|
||||||
return getPath() + ".fill";
|
|
||||||
},
|
|
||||||
icon: "icon-paint-bucket",
|
|
||||||
title: "Set fill color"
|
|
||||||
},
|
|
||||||
stroke = {
|
|
||||||
control: "color-picker",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
property: function () {
|
|
||||||
return getPath() + ".stroke";
|
|
||||||
},
|
|
||||||
icon: "icon-line-horz",
|
|
||||||
title: "Set border color"
|
|
||||||
},
|
|
||||||
color = {
|
|
||||||
control: "color-picker",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
property: function () {
|
|
||||||
return getPath() + ".color";
|
|
||||||
},
|
|
||||||
icon: "icon-font",
|
|
||||||
mandatory: true,
|
|
||||||
title: "Set text color",
|
|
||||||
preventNone: true
|
|
||||||
},
|
|
||||||
size = {
|
|
||||||
control: "select-menu",
|
control: "select-menu",
|
||||||
domainObject: selectedParent,
|
domainObject: selectedParent,
|
||||||
property: function () {
|
applicableSelectedItems: selection.filter(selectionPath => {
|
||||||
return getPath() + ".size";
|
let type = selectionPath[0].context.layoutItem.type;
|
||||||
|
return type === 'text-view' || type === 'telemetry-view';
|
||||||
|
}),
|
||||||
|
property: function (selectionPath) {
|
||||||
|
return getPath(selectionPath) + ".size";
|
||||||
},
|
},
|
||||||
title: "Set text size",
|
title: "Set text size",
|
||||||
options: TEXT_SIZE.map(size => {
|
options: TEXT_SIZE.map(size => {
|
||||||
@ -324,13 +346,128 @@ define([], function () {
|
|||||||
};
|
};
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (layoutItem.type === 'telemetry-view') {
|
function getFillMenu(selectedParent, selection) {
|
||||||
let displayMode = {
|
return {
|
||||||
|
control: "color-picker",
|
||||||
|
domainObject: selectedParent,
|
||||||
|
applicableSelectedItems: selection.filter(selectionPath => {
|
||||||
|
let type = selectionPath[0].context.layoutItem.type;
|
||||||
|
return type === 'text-view' ||
|
||||||
|
type === 'telemetry-view' ||
|
||||||
|
type === 'box-view';
|
||||||
|
}),
|
||||||
|
property: function (selectionPath) {
|
||||||
|
return getPath(selectionPath) + ".fill";
|
||||||
|
},
|
||||||
|
icon: "icon-paint-bucket",
|
||||||
|
title: "Set fill color"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStrokeMenu(selectedParent, selection) {
|
||||||
|
return {
|
||||||
|
control: "color-picker",
|
||||||
|
domainObject: selectedParent,
|
||||||
|
applicableSelectedItems: selection.filter(selectionPath => {
|
||||||
|
let type = selectionPath[0].context.layoutItem.type;
|
||||||
|
return type === 'text-view' ||
|
||||||
|
type === 'telemetry-view' ||
|
||||||
|
type === 'box-view' ||
|
||||||
|
type === 'image-view' ||
|
||||||
|
type === 'line-view';
|
||||||
|
}),
|
||||||
|
property: function (selectionPath) {
|
||||||
|
return getPath(selectionPath) + ".stroke";
|
||||||
|
},
|
||||||
|
icon: "icon-line-horz",
|
||||||
|
title: "Set border color"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTextColorMenu(selectedParent, selection) {
|
||||||
|
return {
|
||||||
|
control: "color-picker",
|
||||||
|
domainObject: selectedParent,
|
||||||
|
applicableSelectedItems: selection.filter(selectionPath => {
|
||||||
|
let type = selectionPath[0].context.layoutItem.type;
|
||||||
|
return type === 'text-view' || type === 'telemetry-view';
|
||||||
|
}),
|
||||||
|
property: function (selectionPath) {
|
||||||
|
return getPath(selectionPath) + ".color";
|
||||||
|
},
|
||||||
|
icon: "icon-font",
|
||||||
|
mandatory: true,
|
||||||
|
title: "Set text color",
|
||||||
|
preventNone: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getURLButton(selectedParent, selection) {
|
||||||
|
return {
|
||||||
|
control: "button",
|
||||||
|
domainObject: selectedParent,
|
||||||
|
applicableSelectedItems: selection.filter(selectionPath => {
|
||||||
|
return selectionPath[0].context.layoutItem.type === 'image-view';
|
||||||
|
}),
|
||||||
|
property: function (selectionPath) {
|
||||||
|
return getPath(selectionPath);
|
||||||
|
},
|
||||||
|
icon: "icon-image",
|
||||||
|
title: "Edit image properties",
|
||||||
|
dialog: DIALOG_FORM['image']
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTextButton(selectedParent, selection) {
|
||||||
|
return {
|
||||||
|
control: "button",
|
||||||
|
domainObject: selectedParent,
|
||||||
|
applicableSelectedItems: selection.filter(selectionPath => {
|
||||||
|
return selectionPath[0].context.layoutItem.type === 'text-view';
|
||||||
|
}),
|
||||||
|
property: function (selectionPath) {
|
||||||
|
return getPath(selectionPath);
|
||||||
|
},
|
||||||
|
icon: "icon-gear",
|
||||||
|
title: "Edit text properties",
|
||||||
|
dialog: DIALOG_FORM['text']
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTelemetryValueMenu(selectionPath, selection) {
|
||||||
|
if (selection.length === 1) {
|
||||||
|
return {
|
||||||
|
control: "select-menu",
|
||||||
|
domainObject: selectionPath[1].context.item,
|
||||||
|
applicableSelectedItems: selection.filter(selectionPath => {
|
||||||
|
return selectionPath[0].context.layoutItem.type === 'telemetry-view';
|
||||||
|
}),
|
||||||
|
property: function (selectionPath) {
|
||||||
|
return getPath(selectionPath) + ".value";
|
||||||
|
},
|
||||||
|
title: "Set value",
|
||||||
|
options: openmct.telemetry.getMetadata(selectionPath[0].context.item).values().map(value => {
|
||||||
|
return {
|
||||||
|
name: value.name,
|
||||||
|
value: value.key
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDisplayModeMenu(selectedParent, selection) {
|
||||||
|
if (selection.length === 1) {
|
||||||
|
return {
|
||||||
control: "select-menu",
|
control: "select-menu",
|
||||||
domainObject: selectedParent,
|
domainObject: selectedParent,
|
||||||
property: function () {
|
applicableSelectedItems: selection.filter(selectionPath => {
|
||||||
return getPath() + ".displayMode";
|
return selectionPath[0].context.layoutItem.type === 'telemetry-view';
|
||||||
|
}),
|
||||||
|
property: function (selectionPath) {
|
||||||
|
return getPath(selectionPath) + ".displayMode";
|
||||||
},
|
},
|
||||||
title: "Set display mode",
|
title: "Set display mode",
|
||||||
options: [
|
options: [
|
||||||
@ -347,146 +484,196 @@ define([], function () {
|
|||||||
value: "value"
|
value: "value"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
value = {
|
|
||||||
control: "select-menu",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
property: function () {
|
|
||||||
return getPath() + ".value";
|
|
||||||
},
|
|
||||||
title: "Set value",
|
|
||||||
options: openmct.telemetry.getMetadata(selectedObject).values().map(value => {
|
|
||||||
return {
|
|
||||||
name: value.name,
|
|
||||||
value: value.key
|
|
||||||
}
|
|
||||||
})
|
|
||||||
};
|
};
|
||||||
toolbar = [
|
|
||||||
displayMode,
|
|
||||||
separator,
|
|
||||||
value,
|
|
||||||
separator,
|
|
||||||
fill,
|
|
||||||
stroke,
|
|
||||||
color,
|
|
||||||
separator,
|
|
||||||
size,
|
|
||||||
separator,
|
|
||||||
stackOrder,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
height,
|
|
||||||
width,
|
|
||||||
useGrid,
|
|
||||||
separator,
|
|
||||||
remove
|
|
||||||
];
|
|
||||||
} else if (layoutItem.type === 'text-view') {
|
|
||||||
let text = {
|
|
||||||
control: "button",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
property: function () {
|
|
||||||
return getPath();
|
|
||||||
},
|
|
||||||
icon: "icon-gear",
|
|
||||||
title: "Edit text properties",
|
|
||||||
dialog: DIALOG_FORM['text']
|
|
||||||
};
|
|
||||||
toolbar = [
|
|
||||||
fill,
|
|
||||||
stroke,
|
|
||||||
separator,
|
|
||||||
color,
|
|
||||||
size,
|
|
||||||
separator,
|
|
||||||
stackOrder,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
height,
|
|
||||||
width,
|
|
||||||
useGrid,
|
|
||||||
separator,
|
|
||||||
text,
|
|
||||||
separator,
|
|
||||||
remove
|
|
||||||
];
|
|
||||||
} else if (layoutItem.type === 'box-view') {
|
|
||||||
toolbar = [
|
|
||||||
fill,
|
|
||||||
stroke,
|
|
||||||
separator,
|
|
||||||
stackOrder,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
height,
|
|
||||||
width,
|
|
||||||
useGrid,
|
|
||||||
separator,
|
|
||||||
remove
|
|
||||||
];
|
|
||||||
} else if (layoutItem.type === 'image-view') {
|
|
||||||
let url = {
|
|
||||||
control: "button",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
property: function () {
|
|
||||||
return getPath();
|
|
||||||
},
|
|
||||||
icon: "icon-image",
|
|
||||||
title: "Edit image properties",
|
|
||||||
dialog: DIALOG_FORM['image']
|
|
||||||
};
|
|
||||||
toolbar = [
|
|
||||||
stroke,
|
|
||||||
separator,
|
|
||||||
stackOrder,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
height,
|
|
||||||
width,
|
|
||||||
useGrid,
|
|
||||||
separator,
|
|
||||||
url,
|
|
||||||
separator,
|
|
||||||
remove
|
|
||||||
];
|
|
||||||
} else if (layoutItem.type === 'line-view') {
|
|
||||||
let x2 = {
|
|
||||||
control: "input",
|
|
||||||
type: "number",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
property: function () {
|
|
||||||
return getPath() + ".x2";
|
|
||||||
},
|
|
||||||
label: "X2:",
|
|
||||||
title: "X2 position"
|
|
||||||
},
|
|
||||||
y2 = {
|
|
||||||
control: "input",
|
|
||||||
type: "number",
|
|
||||||
domainObject: selectedParent,
|
|
||||||
property: function () {
|
|
||||||
return getPath() + ".y2";
|
|
||||||
},
|
|
||||||
label: "Y2:",
|
|
||||||
title: "Y2 position",
|
|
||||||
};
|
|
||||||
toolbar = [
|
|
||||||
stroke,
|
|
||||||
separator,
|
|
||||||
stackOrder,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
x2,
|
|
||||||
y2,
|
|
||||||
useGrid,
|
|
||||||
separator,
|
|
||||||
remove
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return toolbar;
|
function getSeparator() {
|
||||||
|
return {
|
||||||
|
control: "separator"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function isMainLayoutSelected(selectionPath) {
|
||||||
|
let selectedObject = selectionPath[0].context.item;
|
||||||
|
return selectedObject && selectedObject.type === 'layout' &&
|
||||||
|
!selectionPath[0].context.layoutItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isMainLayoutSelected(selection[0])) {
|
||||||
|
return [getAddButton(selection)];
|
||||||
|
}
|
||||||
|
|
||||||
|
let toolbar = {
|
||||||
|
'add-menu': [],
|
||||||
|
'toggle-frame': [],
|
||||||
|
'display-mode': [],
|
||||||
|
'telemetry-value': [],
|
||||||
|
'style': [],
|
||||||
|
'text-style': [],
|
||||||
|
'position': [],
|
||||||
|
'text': [],
|
||||||
|
'url': [],
|
||||||
|
'remove': [],
|
||||||
|
};
|
||||||
|
|
||||||
|
selection.forEach(selectionPath => {
|
||||||
|
let selectedParent = selectionPath[1].context.item;
|
||||||
|
let layoutItem = selectionPath[0].context.layoutItem;
|
||||||
|
|
||||||
|
if (layoutItem.type === 'subobject-view') {
|
||||||
|
if (toolbar['add-menu'].length === 0 && selectionPath[0].context.item.type === 'layout') {
|
||||||
|
toolbar['add-menu'] = [getAddButton(selection, selectionPath)];
|
||||||
|
}
|
||||||
|
if (toolbar['toggle-frame'].length === 0) {
|
||||||
|
toolbar['toggle-frame'] = [getToggleFrameButton(selectedParent, selection)];
|
||||||
|
}
|
||||||
|
if (toolbar['position'].length === 0) {
|
||||||
|
toolbar['position'] = [
|
||||||
|
getStackOrder(selectedParent, selectionPath),
|
||||||
|
getXInput(selectedParent, selection),
|
||||||
|
getYInput(selectedParent, selection),
|
||||||
|
getHeightInput(selectedParent, selection),
|
||||||
|
getWidthInput(selectedParent, selection)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (toolbar['remove'].length === 0) {
|
||||||
|
toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
|
||||||
|
}
|
||||||
|
} else if (layoutItem.type === 'telemetry-view') {
|
||||||
|
if (toolbar['display-mode'].length === 0) {
|
||||||
|
toolbar['display-mode'] = [getDisplayModeMenu(selectedParent, selection)];
|
||||||
|
}
|
||||||
|
if (toolbar['telemetry-value'].length === 0) {
|
||||||
|
toolbar['telemetry-value'] = [getTelemetryValueMenu(selectionPath, selection)];
|
||||||
|
}
|
||||||
|
if (toolbar['style'].length < 2) {
|
||||||
|
toolbar['style'] = [
|
||||||
|
getFillMenu(selectedParent, selection),
|
||||||
|
getStrokeMenu(selectedParent, selection)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (toolbar['text-style'].length === 0) {
|
||||||
|
toolbar['text-style'] = [
|
||||||
|
getTextColorMenu(selectedParent, selection),
|
||||||
|
getTextSizeMenu(selectedParent, selection)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (toolbar['position'].length === 0) {
|
||||||
|
toolbar['position'] = [
|
||||||
|
getStackOrder(selectedParent, selectionPath),
|
||||||
|
getXInput(selectedParent, selection),
|
||||||
|
getYInput(selectedParent, selection),
|
||||||
|
getHeightInput(selectedParent, selection),
|
||||||
|
getWidthInput(selectedParent, selection)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (toolbar['remove'].length === 0) {
|
||||||
|
toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
|
||||||
|
}
|
||||||
|
} else if (layoutItem.type === 'text-view') {
|
||||||
|
if (toolbar['style'].length < 2) {
|
||||||
|
toolbar['style'] = [
|
||||||
|
getFillMenu(selectedParent, selection),
|
||||||
|
getStrokeMenu(selectedParent, selection)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (toolbar['text-style'].length === 0) {
|
||||||
|
toolbar['text-style'] = [
|
||||||
|
getTextColorMenu(selectedParent, selection),
|
||||||
|
getTextSizeMenu(selectedParent, selection)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (toolbar['position'].length === 0) {
|
||||||
|
toolbar['position'] = [
|
||||||
|
getStackOrder(selectedParent, selectionPath),
|
||||||
|
getXInput(selectedParent, selection),
|
||||||
|
getYInput(selectedParent, selection),
|
||||||
|
getHeightInput(selectedParent, selection),
|
||||||
|
getWidthInput(selectedParent, selection)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (toolbar['text'].length === 0) {
|
||||||
|
toolbar['text'] = [getTextButton(selectedParent, selection)];
|
||||||
|
}
|
||||||
|
if (toolbar['remove'].length === 0) {
|
||||||
|
toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
|
||||||
|
}
|
||||||
|
} else if (layoutItem.type === 'box-view') {
|
||||||
|
if (toolbar['style'].length < 2) {
|
||||||
|
toolbar['style'] = [
|
||||||
|
getFillMenu(selectedParent, selection),
|
||||||
|
getStrokeMenu(selectedParent, selection)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (toolbar['position'].length === 0) {
|
||||||
|
toolbar['position'] = [
|
||||||
|
getStackOrder(selectedParent, selectionPath),
|
||||||
|
getXInput(selectedParent, selection),
|
||||||
|
getYInput(selectedParent, selection),
|
||||||
|
getHeightInput(selectedParent, selection),
|
||||||
|
getWidthInput(selectedParent, selection)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (toolbar['remove'].length === 0) {
|
||||||
|
toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
|
||||||
|
}
|
||||||
|
} else if (layoutItem.type === 'image-view') {
|
||||||
|
if (toolbar['style'].length === 0) {
|
||||||
|
toolbar['style'] = [
|
||||||
|
getStrokeMenu(selectedParent, selection)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (toolbar['position'].length === 0) {
|
||||||
|
toolbar['position'] = [
|
||||||
|
getStackOrder(selectedParent, selectionPath),
|
||||||
|
getXInput(selectedParent, selection),
|
||||||
|
getYInput(selectedParent, selection),
|
||||||
|
getHeightInput(selectedParent, selection),
|
||||||
|
getWidthInput(selectedParent, selection)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (toolbar['url'].length === 0) {
|
||||||
|
toolbar['url'] = [getURLButton(selectedParent, selection)];
|
||||||
|
}
|
||||||
|
if (toolbar['remove'].length === 0) {
|
||||||
|
toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
|
||||||
|
}
|
||||||
|
} else if (layoutItem.type === 'line-view') {
|
||||||
|
if (toolbar['style'].length === 0) {
|
||||||
|
toolbar['style'] = [
|
||||||
|
getStrokeMenu(selectedParent, selection)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (toolbar['position'].length === 0) {
|
||||||
|
toolbar['position'] = [
|
||||||
|
getStackOrder(selectedParent, selectionPath),
|
||||||
|
getXInput(selectedParent, selection),
|
||||||
|
getYInput(selectedParent, selection),
|
||||||
|
getX2Input(selectedParent, selection),
|
||||||
|
getY2Input(selectedParent, selection)
|
||||||
|
];
|
||||||
|
}
|
||||||
|
if (toolbar['remove'].length === 0) {
|
||||||
|
toolbar['remove'] = [getRemoveButton(selectedParent, selectionPath, selection)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let toolbarArray = Object.values(toolbar);
|
||||||
|
return _.flatten(toolbarArray.reduce((accumulator, group, index) => {
|
||||||
|
group = group.filter(control => control !== undefined);
|
||||||
|
|
||||||
|
if (group.length > 0) {
|
||||||
|
accumulator.push(group);
|
||||||
|
|
||||||
|
if (index < toolbarArray.length - 1) {
|
||||||
|
accumulator.push(getSeparator());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return accumulator;
|
||||||
|
}, []));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,7 +95,7 @@ define(
|
|||||||
* @param {number[]} pixelDelta the offset from the
|
* @param {number[]} pixelDelta the offset from the
|
||||||
* original position, in pixels
|
* original position, in pixels
|
||||||
*/
|
*/
|
||||||
LayoutDrag.prototype.getAdjustedPosition = function (pixelDelta) {
|
LayoutDrag.prototype.getAdjustedPositionAndDimensions = function (pixelDelta) {
|
||||||
var gridDelta = toGridDelta(this.gridSize, pixelDelta);
|
var gridDelta = toGridDelta(this.gridSize, pixelDelta);
|
||||||
return {
|
return {
|
||||||
position: max(add(
|
position: max(add(
|
||||||
@ -109,6 +109,16 @@ define(
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LayoutDrag.prototype.getAdjustedPosition = function (pixelDelta) {
|
||||||
|
var gridDelta = toGridDelta(this.gridSize, pixelDelta);
|
||||||
|
return {
|
||||||
|
position: max(add(
|
||||||
|
this.rawPosition.position,
|
||||||
|
multiply(gridDelta, this.posFactor)
|
||||||
|
), [0, 0])
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
return LayoutDrag;
|
return LayoutDrag;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<layout-frame :item="item"
|
<layout-frame :item="item"
|
||||||
:grid-size="gridSize"
|
:grid-size="gridSize"
|
||||||
@endDrag="(item, updates) => $emit('endDrag', item, updates)">
|
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||||
|
@endMove="() => $emit('endMove')">
|
||||||
<div class="c-box-view"
|
<div class="c-box-view"
|
||||||
:style="style">
|
:style="style">
|
||||||
</div>
|
</div>
|
||||||
@ -54,8 +55,7 @@
|
|||||||
x: 1,
|
x: 1,
|
||||||
y: 1,
|
y: 1,
|
||||||
width: 10,
|
width: 10,
|
||||||
height: 5,
|
height: 5
|
||||||
useGrid: true
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
|
@ -23,8 +23,11 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="l-layout"
|
<div class="l-layout"
|
||||||
@dragover="handleDragOver"
|
@dragover="handleDragOver"
|
||||||
@click="bypassSelection"
|
@click.capture="bypassSelection"
|
||||||
@drop="handleDrop">
|
@drop="handleDrop"
|
||||||
|
:class="{
|
||||||
|
'is-multi-selected': selectedLayoutItems.length > 1
|
||||||
|
}">
|
||||||
<!-- Background grid -->
|
<!-- Background grid -->
|
||||||
<div class="l-layout__grid-holder c-grid">
|
<div class="l-layout__grid-holder c-grid">
|
||||||
<div class="c-grid__x l-grid l-grid-x"
|
<div class="c-grid__x l-grid l-grid-x"
|
||||||
@ -39,18 +42,38 @@
|
|||||||
:is="item.type"
|
:is="item.type"
|
||||||
:item="item"
|
:item="item"
|
||||||
:key="item.id"
|
:key="item.id"
|
||||||
:gridSize="item.useGrid ? gridSize : [1, 1]"
|
:gridSize="gridSize"
|
||||||
:initSelect="initSelectIndex === index"
|
:initSelect="initSelectIndex === index"
|
||||||
:index="index"
|
:index="index"
|
||||||
@endDrag="endDrag"
|
:multiSelect="selectedLayoutItems.length > 1"
|
||||||
>
|
@move="move"
|
||||||
|
@endMove="endMove"
|
||||||
|
@endLineResize='endLineResize'>
|
||||||
</component>
|
</component>
|
||||||
|
<edit-marquee v-if='showMarquee'
|
||||||
|
:gridSize="gridSize"
|
||||||
|
:selectedLayoutItems="selectedLayoutItems"
|
||||||
|
@endResize="endResize">
|
||||||
|
</edit-marquee>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "~styles/sass-base";
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
|
@mixin displayMarquee($c) {
|
||||||
|
> .c-frame-edit {
|
||||||
|
// All other frames
|
||||||
|
//@include test($c, 0.4);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
> .c-frame > .c-frame-edit {
|
||||||
|
// Line object frame
|
||||||
|
//@include test($c, 0.4);
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.l-layout {
|
.l-layout {
|
||||||
@include abs();
|
@include abs();
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -70,7 +93,7 @@
|
|||||||
.l-shell__main-container {
|
.l-shell__main-container {
|
||||||
&[s-selected],
|
&[s-selected],
|
||||||
&[s-selected-parent] {
|
&[s-selected-parent] {
|
||||||
// Display grid in main layout holder when editing
|
// Display grid and allow edit marquee to display in main layout holder when editing
|
||||||
> .l-layout {
|
> .l-layout {
|
||||||
background: $editUIGridColorBg;
|
background: $editUIGridColorBg;
|
||||||
|
|
||||||
@ -84,7 +107,7 @@
|
|||||||
.l-layout__frame {
|
.l-layout__frame {
|
||||||
&[s-selected],
|
&[s-selected],
|
||||||
&[s-selected-parent] {
|
&[s-selected-parent] {
|
||||||
// Display grid in nested layouts when editing
|
// Display grid and allow edit marquee to display in nested layouts when editing
|
||||||
> * > * > .l-layout {
|
> * > * > .l-layout {
|
||||||
background: $editUIGridColorBg;
|
background: $editUIGridColorBg;
|
||||||
box-shadow: inset $editUIGridColorFg 0 0 2px 1px;
|
box-shadow: inset $editUIGridColorFg 0 0 2px 1px;
|
||||||
@ -95,10 +118,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************** EDIT MARQUEE CONTROL */
|
||||||
|
*[s-selected-parent] {
|
||||||
|
> .l-layout {
|
||||||
|
// When main shell layout is the parent
|
||||||
|
@include displayMarquee(deeppink);
|
||||||
|
}
|
||||||
|
> * > * > * {
|
||||||
|
// When a sub-layout is the parent
|
||||||
|
@include displayMarquee(blue);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import uuid from 'uuid';
|
import uuid from 'uuid';
|
||||||
|
|
||||||
@ -108,6 +142,7 @@
|
|||||||
import TextView from './TextView.vue'
|
import TextView from './TextView.vue'
|
||||||
import LineView from './LineView.vue'
|
import LineView from './LineView.vue'
|
||||||
import ImageView from './ImageView.vue'
|
import ImageView from './ImageView.vue'
|
||||||
|
import EditMarquee from './EditMarquee.vue'
|
||||||
|
|
||||||
const ITEM_TYPE_VIEW_MAP = {
|
const ITEM_TYPE_VIEW_MAP = {
|
||||||
'subobject-view': SubobjectView,
|
'subobject-view': SubobjectView,
|
||||||
@ -123,9 +158,11 @@
|
|||||||
down: -1,
|
down: -1,
|
||||||
bottom: Number.NEGATIVE_INFINITY
|
bottom: Number.NEGATIVE_INFINITY
|
||||||
};
|
};
|
||||||
|
|
||||||
const DRAG_OBJECT_TRANSFER_PREFIX = 'openmct/domain-object/';
|
const DRAG_OBJECT_TRANSFER_PREFIX = 'openmct/domain-object/';
|
||||||
|
|
||||||
|
let components = ITEM_TYPE_VIEW_MAP;
|
||||||
|
components['edit-marquee'] = EditMarquee;
|
||||||
|
|
||||||
function getItemDefinition(itemType, ...options) {
|
function getItemDefinition(itemType, ...options) {
|
||||||
let itemView = ITEM_TYPE_VIEW_MAP[itemType];
|
let itemView = ITEM_TYPE_VIEW_MAP[itemType];
|
||||||
|
|
||||||
@ -141,7 +178,8 @@
|
|||||||
let domainObject = JSON.parse(JSON.stringify(this.domainObject));
|
let domainObject = JSON.parse(JSON.stringify(this.domainObject));
|
||||||
return {
|
return {
|
||||||
internalDomainObject: domainObject,
|
internalDomainObject: domainObject,
|
||||||
initSelectIndex: undefined
|
initSelectIndex: undefined,
|
||||||
|
selection: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -150,82 +188,115 @@
|
|||||||
},
|
},
|
||||||
layoutItems() {
|
layoutItems() {
|
||||||
return this.internalDomainObject.configuration.items;
|
return this.internalDomainObject.configuration.items;
|
||||||
|
},
|
||||||
|
selectedLayoutItems() {
|
||||||
|
return this.layoutItems.filter(item => {
|
||||||
|
return this.itemIsInCurrentSelection(item);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
showMarquee() {
|
||||||
|
let selectionPath = this.selection[0];
|
||||||
|
let singleSelectedLine = this.selection.length === 1 &&
|
||||||
|
selectionPath[0].context.layoutItem && selectionPath[0].context.layoutItem.type === 'line-view';
|
||||||
|
return selectionPath && selectionPath.length > 1 && !singleSelectedLine;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
inject: ['openmct', 'options'],
|
inject: ['openmct', 'options'],
|
||||||
props: ['domainObject'],
|
props: ['domainObject'],
|
||||||
components: ITEM_TYPE_VIEW_MAP,
|
components: components,
|
||||||
methods: {
|
methods: {
|
||||||
addElement(itemType, element) {
|
addElement(itemType, element) {
|
||||||
this.addItem(itemType + '-view', element);
|
this.addItem(itemType + '-view', element);
|
||||||
},
|
},
|
||||||
setSelection(selection) {
|
setSelection(selection) {
|
||||||
if (selection.length === 0) {
|
this.selection = selection;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.removeSelectionListener) {
|
|
||||||
this.removeSelectionListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
let itemIndex = selection[0].context.index;
|
|
||||||
|
|
||||||
if (itemIndex !== undefined) {
|
|
||||||
this.attachSelectionListener(itemIndex);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
attachSelectionListener(index) {
|
itemIsInCurrentSelection(item) {
|
||||||
let path = `configuration.items[${index}].useGrid`;
|
return this.selection.some(selectionPath =>
|
||||||
this.removeSelectionListener = this.openmct.objects.observe(this.internalDomainObject, path, function (value) {
|
selectionPath[0].context.layoutItem && selectionPath[0].context.layoutItem.id === item.id);
|
||||||
let item = this.layoutItems[index];
|
|
||||||
|
|
||||||
if (value) {
|
|
||||||
item.x = Math.round(item.x / this.gridSize[0]);
|
|
||||||
item.y = Math.round(item.y / this.gridSize[1]);
|
|
||||||
item.width = Math.round(item.width / this.gridSize[0]);
|
|
||||||
item.height = Math.round(item.height / this.gridSize[1]);
|
|
||||||
|
|
||||||
if (item.x2) {
|
|
||||||
item.x2 = Math.round(item.x2 / this.gridSize[0]);
|
|
||||||
}
|
|
||||||
if (item.y2) {
|
|
||||||
item.y2 = Math.round(item.y2 / this.gridSize[1]);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
item.x = this.gridSize[0] * item.x;
|
|
||||||
item.y = this.gridSize[1] * item.y;
|
|
||||||
item.width = this.gridSize[0] * item.width;
|
|
||||||
item.height = this.gridSize[1] * item.height;
|
|
||||||
|
|
||||||
if (item.x2) {
|
|
||||||
item.x2 = this.gridSize[0] * item.x2;
|
|
||||||
}
|
|
||||||
if (item.y2) {
|
|
||||||
item.y2 = this.gridSize[1] * item.y2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
item.useGrid = value;
|
|
||||||
this.mutate(`configuration.items[${index}]`, item);
|
|
||||||
}.bind(this));
|
|
||||||
},
|
},
|
||||||
bypassSelection($event) {
|
bypassSelection($event) {
|
||||||
if (this.dragInProgress) {
|
if (this.dragInProgress) {
|
||||||
if ($event) {
|
if ($event) {
|
||||||
$event.stopImmediatePropagation();
|
$event.stopImmediatePropagation();
|
||||||
}
|
}
|
||||||
|
this.dragInProgress = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
endDrag(item, updates) {
|
endLineResize(item, updates) {
|
||||||
this.dragInProgress = true;
|
this.dragInProgress = true;
|
||||||
setTimeout(function () {
|
|
||||||
this.dragInProgress = false;
|
|
||||||
}.bind(this), 0);
|
|
||||||
|
|
||||||
let index = this.layoutItems.indexOf(item);
|
let index = this.layoutItems.indexOf(item);
|
||||||
Object.assign(item, updates);
|
Object.assign(item, updates);
|
||||||
this.mutate(`configuration.items[${index}]`, item);
|
this.mutate(`configuration.items[${index}]`, item);
|
||||||
},
|
},
|
||||||
|
endResize(scaleWidth, scaleHeight, marqueeStart, marqueeOffset) {
|
||||||
|
this.dragInProgress = true;
|
||||||
|
this.layoutItems.forEach(item => {
|
||||||
|
if (this.itemIsInCurrentSelection(item)) {
|
||||||
|
let itemXInMarqueeSpace = item.x - marqueeStart.x;
|
||||||
|
let itemXInMarqueeSpaceAfterScale = Math.round(itemXInMarqueeSpace * scaleWidth);
|
||||||
|
item.x = itemXInMarqueeSpaceAfterScale + marqueeOffset.x + marqueeStart.x;
|
||||||
|
|
||||||
|
let itemYInMarqueeSpace = item.y - marqueeStart.y;
|
||||||
|
let itemYInMarqueeSpaceAfterScale = Math.round(itemYInMarqueeSpace * scaleHeight);
|
||||||
|
item.y = itemYInMarqueeSpaceAfterScale + marqueeOffset.y + marqueeStart.y;
|
||||||
|
|
||||||
|
if (item.x2) {
|
||||||
|
let itemX2InMarqueeSpace = item.x2 - marqueeStart.x;
|
||||||
|
let itemX2InMarqueeSpaceAfterScale = Math.round(itemX2InMarqueeSpace * scaleWidth);
|
||||||
|
item.x2 = itemX2InMarqueeSpaceAfterScale + marqueeOffset.x + marqueeStart.x;
|
||||||
|
} else {
|
||||||
|
item.width = Math.round(item.width * scaleWidth);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.y2) {
|
||||||
|
let itemY2InMarqueeSpace = item.y2 - marqueeStart.y;
|
||||||
|
let itemY2InMarqueeSpaceAfterScale = Math.round(itemY2InMarqueeSpace * scaleHeight);
|
||||||
|
item.y2 = itemY2InMarqueeSpaceAfterScale + marqueeOffset.y + marqueeStart.y;
|
||||||
|
} else {
|
||||||
|
item.height = Math.round(item.height * scaleHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.mutate("configuration.items", this.layoutItems);
|
||||||
|
},
|
||||||
|
move(gridDelta) {
|
||||||
|
this.dragInProgress = true;
|
||||||
|
|
||||||
|
if (!this.initialPositions) {
|
||||||
|
this.initialPositions = {};
|
||||||
|
_.cloneDeep(this.selectedLayoutItems).forEach(selectedItem => {
|
||||||
|
if (selectedItem.type === 'line-view') {
|
||||||
|
this.initialPositions[selectedItem.id] = [selectedItem.x, selectedItem.y, selectedItem.x2, selectedItem.y2];
|
||||||
|
} else {
|
||||||
|
this.initialPositions[selectedItem.id] = [selectedItem.x, selectedItem.y];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let layoutItems = this.layoutItems.map(item => {
|
||||||
|
if (this.initialPositions[item.id]) {
|
||||||
|
let startingPosition = this.initialPositions[item.id];
|
||||||
|
let [startingX, startingY, startingX2, startingY2] = startingPosition;
|
||||||
|
item.x = startingX + gridDelta[0];
|
||||||
|
item.y = startingY + gridDelta[1];
|
||||||
|
|
||||||
|
if (item.x2) {
|
||||||
|
item.x2 = startingX2 + gridDelta[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.y2) {
|
||||||
|
item.y2 = startingY2 + gridDelta[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
endMove() {
|
||||||
|
this.mutate('configuration.items', this.layoutItems);
|
||||||
|
this.initialPositions = undefined;
|
||||||
|
},
|
||||||
mutate(path, value) {
|
mutate(path, value) {
|
||||||
this.openmct.objects.mutate(this.internalDomainObject, path, value);
|
this.openmct.objects.mutate(this.internalDomainObject, path, value);
|
||||||
},
|
},
|
||||||
@ -313,11 +384,15 @@
|
|||||||
this.objectViewMap[keyString] = true;
|
this.objectViewMap[keyString] = true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
removeItem(item, index) {
|
removeItem(selectedItems) {
|
||||||
|
let indices = [];
|
||||||
this.initSelectIndex = -1;
|
this.initSelectIndex = -1;
|
||||||
this.layoutItems.splice(index, 1);
|
selectedItems.forEach(selectedItem => {
|
||||||
|
indices.push(selectedItem[0].context.index);
|
||||||
|
this.untrackItem(selectedItem[0].context.layoutItem);
|
||||||
|
});
|
||||||
|
_.pullAt(this.layoutItems, indices);
|
||||||
this.mutate("configuration.items", this.layoutItems);
|
this.mutate("configuration.items", this.layoutItems);
|
||||||
this.untrackItem(item);
|
|
||||||
this.$el.click();
|
this.$el.click();
|
||||||
},
|
},
|
||||||
untrackItem(item) {
|
untrackItem(item) {
|
||||||
@ -383,20 +458,74 @@
|
|||||||
this.mutate("configuration.items", layoutItems);
|
this.mutate("configuration.items", layoutItems);
|
||||||
this.$el.click();
|
this.$el.click();
|
||||||
},
|
},
|
||||||
orderItem(position, index) {
|
orderItem(position, selectedItems) {
|
||||||
let delta = ORDERS[position];
|
let delta = ORDERS[position];
|
||||||
let newIndex = Math.max(Math.min(index + delta, this.layoutItems.length - 1), 0);
|
let indices = [];
|
||||||
let item = this.layoutItems[index];
|
let newIndex = -1;
|
||||||
|
let items = [];
|
||||||
|
|
||||||
if (newIndex !== index) {
|
Object.assign(items, this.layoutItems);
|
||||||
this.layoutItems.splice(index, 1);
|
this.selectedLayoutItems.forEach(selectedItem => {
|
||||||
this.layoutItems.splice(newIndex, 0, item);
|
indices.push(this.layoutItems.indexOf(selectedItem));
|
||||||
this.mutate('configuration.items', this.layoutItems);
|
});
|
||||||
|
indices.sort((a, b) => a - b);
|
||||||
|
|
||||||
if (this.removeSelectionListener) {
|
if (position === 'top' || position === 'up') {
|
||||||
this.removeSelectionListener();
|
indices.reverse();
|
||||||
this.attachSelectionListener(newIndex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (position === 'top' || position === 'bottom') {
|
||||||
|
this.moveToTopOrBottom(position, indices, items, delta);
|
||||||
|
} else {
|
||||||
|
this.moveUpOrDown(position, indices, items, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mutate('configuration.items', this.layoutItems);
|
||||||
|
},
|
||||||
|
moveUpOrDown(position, indices, items, delta) {
|
||||||
|
let previousItemIndex = -1;
|
||||||
|
let newIndex = -1;
|
||||||
|
|
||||||
|
indices.forEach((itemIndex, index) => {
|
||||||
|
let isAdjacentItemSelected = position === 'up' ?
|
||||||
|
itemIndex + 1 === previousItemIndex :
|
||||||
|
itemIndex - 1 === previousItemIndex;
|
||||||
|
|
||||||
|
if (index > 0 && isAdjacentItemSelected) {
|
||||||
|
if (position === 'up') {
|
||||||
|
newIndex -= 1;
|
||||||
|
} else {
|
||||||
|
newIndex += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
newIndex = Math.max(Math.min(itemIndex + delta, this.layoutItems.length - 1), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
previousItemIndex = itemIndex;
|
||||||
|
this.updateItemOrder(newIndex, itemIndex, items);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
moveToTopOrBottom(position, indices, items, delta) {
|
||||||
|
let newIndex = -1;
|
||||||
|
|
||||||
|
indices.forEach((itemIndex, index) => {
|
||||||
|
if (index === 0) {
|
||||||
|
newIndex = Math.max(Math.min(itemIndex + delta, this.layoutItems.length - 1), 0);
|
||||||
|
} else {
|
||||||
|
if (position === 'top') {
|
||||||
|
newIndex -= 1;
|
||||||
|
} else {
|
||||||
|
newIndex += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateItemOrder(newIndex, itemIndex, items);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
updateItemOrder(newIndex, itemIndex, items) {
|
||||||
|
if (newIndex !== itemIndex) {
|
||||||
|
this.layoutItems.splice(itemIndex, 1);
|
||||||
|
this.layoutItems.splice(newIndex, 0, items[itemIndex]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -412,14 +541,10 @@
|
|||||||
this.composition.load();
|
this.composition.load();
|
||||||
},
|
},
|
||||||
destroyed: function () {
|
destroyed: function () {
|
||||||
this.openmct.off('change', this.setSelection);
|
this.openmct.selection.off('change', this.setSelection);
|
||||||
this.composition.off('add', this.addChild);
|
this.composition.off('add', this.addChild);
|
||||||
this.composition.off('remove', this.removeChild);
|
this.composition.off('remove', this.removeChild);
|
||||||
this.unlisten();
|
this.unlisten();
|
||||||
|
|
||||||
if (this.removeSelectionListener) {
|
|
||||||
this.removeSelectionListener();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
233
src/plugins/displayLayout/components/EditMarquee.vue
Normal file
233
src/plugins/displayLayout/components/EditMarquee.vue
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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>
|
||||||
|
<!-- Resize handles -->
|
||||||
|
<div class="c-frame-edit" :style="style">
|
||||||
|
<div class="c-frame-edit__handle c-frame-edit__handle--nw"
|
||||||
|
@mousedown="startResize([1,1], [-1,-1], $event)"></div>
|
||||||
|
<div class="c-frame-edit__handle c-frame-edit__handle--ne"
|
||||||
|
@mousedown="startResize([0,1], [1,-1], $event)"></div>
|
||||||
|
<div class="c-frame-edit__handle c-frame-edit__handle--sw"
|
||||||
|
@mousedown="startResize([1,0], [-1,1], $event)"></div>
|
||||||
|
<div class="c-frame-edit__handle c-frame-edit__handle--se"
|
||||||
|
@mousedown="startResize([0,0], [1,1], $event)"></div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
|
.c-frame-edit {
|
||||||
|
// In Layouts, this is the editing rect and handles
|
||||||
|
display: none; // Set to display: block in DisplayLayout.vue
|
||||||
|
pointer-events: none;
|
||||||
|
@include abs();
|
||||||
|
border: $editMarqueeBorder;
|
||||||
|
|
||||||
|
&__handle {
|
||||||
|
$d: 6px;
|
||||||
|
$o: floor($d * -0.5);
|
||||||
|
background: $editFrameColorHandleFg;
|
||||||
|
box-shadow: $editFrameColorHandleBg 0 0 0 2px;
|
||||||
|
pointer-events: all;
|
||||||
|
position: absolute;
|
||||||
|
width: $d; height: $d;
|
||||||
|
top: auto; right: auto; bottom: auto; left: auto;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
// Extended hit area
|
||||||
|
@include abs(-10px);
|
||||||
|
content: '';
|
||||||
|
display: block;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $editUIColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--nwse {
|
||||||
|
cursor: nwse-resize;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--nw {
|
||||||
|
cursor: nw-resize;
|
||||||
|
left: $o; top: $o;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--ne {
|
||||||
|
cursor: ne-resize;
|
||||||
|
right: $o; top: $o;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--se {
|
||||||
|
cursor: se-resize;
|
||||||
|
right: $o; bottom: $o;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--sw {
|
||||||
|
cursor: sw-resize;
|
||||||
|
left: $o; bottom: $o;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import LayoutDrag from './../LayoutDrag'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
inject: ['openmct'],
|
||||||
|
props: {
|
||||||
|
selectedLayoutItems: Array,
|
||||||
|
gridSize: Array
|
||||||
|
},
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
dragPosition: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
style() {
|
||||||
|
let x = Number.POSITIVE_INFINITY;
|
||||||
|
let y = Number.POSITIVE_INFINITY;
|
||||||
|
let width = Number.NEGATIVE_INFINITY;
|
||||||
|
let height = Number.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
|
this.selectedLayoutItems.forEach(item => {
|
||||||
|
if (item.x2) {
|
||||||
|
let lineWidth = Math.abs(item.x - item.x2);
|
||||||
|
let lineMinX = Math.min(item.x, item.x2);
|
||||||
|
x = Math.min(lineMinX, x);
|
||||||
|
width = Math.max(lineWidth + lineMinX, width);
|
||||||
|
} else {
|
||||||
|
x = Math.min(item.x, x);
|
||||||
|
width = Math.max(item.width + item.x, width);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.y2) {
|
||||||
|
let lineHeight = Math.abs(item.y - item.y2);
|
||||||
|
let lineMinY = Math.min(item.y, item.y2);
|
||||||
|
y = Math.min(lineMinY, y);
|
||||||
|
height = Math.max(lineHeight + lineMinY, height);
|
||||||
|
} else {
|
||||||
|
y = Math.min(item.y, y);
|
||||||
|
height = Math.max(item.height + item.y, height);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.dragPosition) {
|
||||||
|
[x, y] = this.dragPosition.position;
|
||||||
|
[width, height] = this.dragPosition.dimensions;
|
||||||
|
} else {
|
||||||
|
width = width - x;
|
||||||
|
height = height - y;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.marqueePosition = {
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
width: width,
|
||||||
|
height: height
|
||||||
|
}
|
||||||
|
return this.getMarqueeStyle(x, y, width, height);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
getMarqueeStyle(x, y, width, height) {
|
||||||
|
return {
|
||||||
|
left: (this.gridSize[0] * x) + 'px',
|
||||||
|
top: (this.gridSize[1] * y) + 'px',
|
||||||
|
width: (this.gridSize[0] * width) + 'px',
|
||||||
|
height: (this.gridSize[1] * height) + 'px'
|
||||||
|
};
|
||||||
|
},
|
||||||
|
updatePosition(event) {
|
||||||
|
let currentPosition = [event.pageX, event.pageY];
|
||||||
|
this.initialPosition = this.initialPosition || currentPosition;
|
||||||
|
this.delta = currentPosition.map(function (value, index) {
|
||||||
|
return value - this.initialPosition[index];
|
||||||
|
}.bind(this));
|
||||||
|
},
|
||||||
|
startResize(posFactor, dimFactor, event) {
|
||||||
|
document.body.addEventListener('mousemove', this.continueResize);
|
||||||
|
document.body.addEventListener('mouseup', this.endResize);
|
||||||
|
this.marqueeStartPosition = {
|
||||||
|
position: [this.marqueePosition.x, this.marqueePosition.y],
|
||||||
|
dimensions: [this.marqueePosition.width, this.marqueePosition.height]
|
||||||
|
};
|
||||||
|
this.updatePosition(event);
|
||||||
|
this.activeDrag = new LayoutDrag(this.marqueeStartPosition, posFactor, dimFactor, this.gridSize);
|
||||||
|
event.preventDefault();
|
||||||
|
},
|
||||||
|
continueResize(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
this.updatePosition(event);
|
||||||
|
this.dragPosition = this.activeDrag.getAdjustedPositionAndDimensions(this.delta);
|
||||||
|
},
|
||||||
|
endResize(event) {
|
||||||
|
document.body.removeEventListener('mousemove', this.continueResize);
|
||||||
|
document.body.removeEventListener('mouseup', this.endResize);
|
||||||
|
this.continueResize(event);
|
||||||
|
|
||||||
|
let marqueeStartWidth = this.marqueeStartPosition.dimensions[0];
|
||||||
|
let marqueeStartHeight = this.marqueeStartPosition.dimensions[1];
|
||||||
|
let marqueeStartX = this.marqueeStartPosition.position[0];
|
||||||
|
let marqueeStartY = this.marqueeStartPosition.position[1];
|
||||||
|
|
||||||
|
let marqueeEndX = this.dragPosition.position[0];
|
||||||
|
let marqueeEndY = this.dragPosition.position[1];
|
||||||
|
let marqueeEndWidth = this.dragPosition.dimensions[0];
|
||||||
|
let marqueeEndHeight = this.dragPosition.dimensions[1];
|
||||||
|
|
||||||
|
let scaleWidth = marqueeEndWidth / marqueeStartWidth;
|
||||||
|
let scaleHeight = marqueeEndHeight / marqueeStartHeight;
|
||||||
|
|
||||||
|
let marqueeStart = {
|
||||||
|
x: marqueeStartX,
|
||||||
|
y: marqueeStartY,
|
||||||
|
height: marqueeStartWidth,
|
||||||
|
width: marqueeStartHeight
|
||||||
|
};
|
||||||
|
let marqueeEnd = {
|
||||||
|
x: marqueeEndX,
|
||||||
|
y: marqueeEndY,
|
||||||
|
width: marqueeEndWidth,
|
||||||
|
height: marqueeEndHeight
|
||||||
|
};
|
||||||
|
let marqueeOffset = {
|
||||||
|
x: marqueeEnd.x - marqueeStart.x,
|
||||||
|
y: marqueeEnd.y - marqueeStart.y
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$emit('endResize', scaleWidth, scaleHeight, marqueeStart, marqueeOffset);
|
||||||
|
this.dragPosition = undefined;
|
||||||
|
this.initialPosition = undefined;
|
||||||
|
this.marqueeStartPosition = undefined;
|
||||||
|
this.delta = undefined;
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
@ -23,7 +23,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<layout-frame :item="item"
|
<layout-frame :item="item"
|
||||||
:grid-size="gridSize"
|
:grid-size="gridSize"
|
||||||
@endDrag="(item, updates) => $emit('endDrag', item, updates)">
|
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||||
|
@endMove="() => $emit('endMove')">
|
||||||
<div class="c-image-view"
|
<div class="c-image-view"
|
||||||
:style="style">
|
:style="style">
|
||||||
</div>
|
</div>
|
||||||
@ -56,8 +57,7 @@
|
|||||||
y: 1,
|
y: 1,
|
||||||
width: 10,
|
width: 10,
|
||||||
height: 5,
|
height: 5,
|
||||||
url: element.url,
|
url: element.url
|
||||||
useGrid: true
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
|
@ -24,25 +24,14 @@
|
|||||||
<div class="l-layout__frame c-frame"
|
<div class="l-layout__frame c-frame"
|
||||||
:class="{
|
:class="{
|
||||||
'no-frame': !item.hasFrame,
|
'no-frame': !item.hasFrame,
|
||||||
'u-inspectable': inspectable,
|
'u-inspectable': inspectable
|
||||||
'is-resizing': isResizing
|
|
||||||
}"
|
}"
|
||||||
:style="style">
|
:style="style">
|
||||||
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
|
|
||||||
<!-- Drag handles -->
|
|
||||||
<div class="c-frame-edit">
|
|
||||||
<div class="c-frame-edit__move"
|
<div class="c-frame-edit__move"
|
||||||
@mousedown="startDrag([1,1], [0,0], $event, 'move')"></div>
|
@mousedown="startMove([1,1], [0,0], $event)">
|
||||||
<div class="c-frame-edit__handle c-frame-edit__handle--nw"
|
|
||||||
@mousedown="startDrag([1,1], [-1,-1], $event, 'resize')"></div>
|
|
||||||
<div class="c-frame-edit__handle c-frame-edit__handle--ne"
|
|
||||||
@mousedown="startDrag([0,1], [1,-1], $event, 'resize')"></div>
|
|
||||||
<div class="c-frame-edit__handle c-frame-edit__handle--sw"
|
|
||||||
@mousedown="startDrag([1,0], [-1,1], $event, 'resize')"></div>
|
|
||||||
<div class="c-frame-edit__handle c-frame-edit__handle--se"
|
|
||||||
@mousedown="startDrag([0,0], [1,1], $event, 'resize')"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -50,7 +39,7 @@
|
|||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import "~styles/sass-base";
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
/******************************* FRAME */
|
/******************* FRAME */
|
||||||
.c-frame {
|
.c-frame {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
@ -61,74 +50,72 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.c-frame-edit {
|
.c-frame-edit__move {
|
||||||
// In Layouts, this is the editing rect and handles
|
|
||||||
// In Fixed Position, this is a wrapper element
|
|
||||||
@include abs();
|
|
||||||
display: none;
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
&__move {
|
.is-editing {
|
||||||
@include abs();
|
/******************* STYLES FOR C-FRAME WHILE EDITING */
|
||||||
|
.c-frame {
|
||||||
|
&:not([s-selected]) {
|
||||||
|
&:hover {
|
||||||
|
border: $editFrameBorderHov;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[s-selected] {
|
||||||
|
// All frames selected while editing
|
||||||
|
border: $editFrameSelectedBorder;
|
||||||
|
box-shadow: $editFrameSelectedShdw;
|
||||||
|
|
||||||
|
.c-frame-edit__move {
|
||||||
cursor: move;
|
cursor: move;
|
||||||
}
|
}
|
||||||
|
|
||||||
&__handle {
|
|
||||||
$d: 6px;
|
|
||||||
$o: floor($d * -0.5);
|
|
||||||
background: $editFrameColorHandleFg;
|
|
||||||
box-shadow: $editFrameColorHandleBg 0 0 0 2px;
|
|
||||||
display: none; // Set to block via s-selected selector
|
|
||||||
position: absolute;
|
|
||||||
width: $d; height: $d;
|
|
||||||
top: auto; right: auto; bottom: auto; left: auto;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
// Extended hit area
|
|
||||||
@include abs(-10px);
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: $editUIColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--nwse {
|
|
||||||
cursor: nwse-resize;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--nw {
|
|
||||||
cursor: nw-resize;
|
|
||||||
left: $o; top: $o;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--ne {
|
|
||||||
cursor: ne-resize;
|
|
||||||
right: $o; top: $o;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--se {
|
|
||||||
cursor: se-resize;
|
|
||||||
right: $o; bottom: $o;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--sw {
|
|
||||||
cursor: sw-resize;
|
|
||||||
left: $o; bottom: $o;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.c-so-view.has-complex-content + .c-frame-edit {
|
/******************* DEFAULT STYLES FOR -EDIT__MOVE */
|
||||||
// Target frames that hold domain objects that include header elements, as opposed to drawing and alpha objects
|
// All object types
|
||||||
// Make the __move element a more affordable drag UI element
|
|
||||||
.c-frame-edit__move {
|
.c-frame-edit__move {
|
||||||
|
@include abs();
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Has-complex-content objects
|
||||||
|
.c-so-view.has-complex-content {
|
||||||
|
transition: $transOut;
|
||||||
|
transition-delay: $moveBarOutDelay;
|
||||||
|
|
||||||
|
> .c-so-view__local-controls {
|
||||||
|
transition: transform 250ms ease-in-out;
|
||||||
|
transition-delay: $moveBarOutDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .c-frame-edit__move {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.l-layout {
|
||||||
|
/******************* 0 - 1 ITEM SELECTED */
|
||||||
|
&:not(.is-multi-selected) {
|
||||||
|
> .l-layout__frame[s-selected] {
|
||||||
|
> .c-so-view.has-complex-content {
|
||||||
|
> .c-so-view__local-controls {
|
||||||
|
transition: transform $transOutTime ease-in-out;
|
||||||
|
transition-delay: $moveBarOutDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .c-frame-edit__move {
|
||||||
|
transition: $transOut;
|
||||||
|
transition-delay: $moveBarOutDelay;
|
||||||
@include userSelectNone();
|
@include userSelectNone();
|
||||||
background: $editFrameMovebarColorBg;
|
background: $editFrameMovebarColorBg;
|
||||||
box-shadow: rgba(black, 0.2) 0 1px;
|
box-shadow: rgba(black, 0.2) 0 1px;
|
||||||
bottom: auto;
|
bottom: auto;
|
||||||
height: 0; // Height is set on hover on s-selected.c-frame
|
display: block;
|
||||||
|
height: 0; // Height is set on hover below
|
||||||
opacity: 0.8;
|
opacity: 0.8;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
@ -143,86 +130,48 @@
|
|||||||
content: '';
|
content: '';
|
||||||
display: block;
|
display: block;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: $tbOffset; right: $lrOffset; bottom: $tbOffset; left: $lrOffset;
|
top: $tbOffset;
|
||||||
|
right: $lrOffset;
|
||||||
|
bottom: $tbOffset;
|
||||||
|
left: $lrOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $editFrameHovMovebarColorBg;
|
> .c-so-view.has-complex-content {
|
||||||
&:before { @include grippy($editFrameHovMovebarColorFg); }
|
transition: $transIn;
|
||||||
|
transition-delay: 0s;
|
||||||
|
padding-top: $editFrameMovebarH + $interiorMarginSm;
|
||||||
|
|
||||||
|
> .c-so-view__local-controls {
|
||||||
|
transform: translateY($editFrameMovebarH);
|
||||||
|
transition: transform $transInTime ease-in-out;
|
||||||
|
transition-delay: 0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ .c-frame-edit__move {
|
||||||
|
transition: $transIn;
|
||||||
|
transition-delay: 0s;
|
||||||
|
height: $editFrameMovebarH;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.is-editing {
|
/******************* > 1 ITEMS SELECTED */
|
||||||
.c-frame {
|
&.is-multi-selected {
|
||||||
&.no-frame {
|
.l-layout__frame[s-selected] {
|
||||||
border: $editFrameBorder; // Base border style for a frame element while editing.
|
> .c-so-view.has-complex-content + .c-frame-edit__move {
|
||||||
}
|
|
||||||
|
|
||||||
&-edit {
|
|
||||||
display: contents;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-edit__move,
|
|
||||||
.c-so-view {
|
|
||||||
transition: $transOut;
|
|
||||||
transition-delay: $moveBarOutDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not([s-selected]) {
|
|
||||||
&:hover {
|
|
||||||
border: $editFrameBorderHov;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&[s-selected] {
|
|
||||||
// All frames selected while editing
|
|
||||||
border: $editFrameSelectedBorder;
|
|
||||||
box-shadow: $editFrameSelectedShdw;
|
|
||||||
|
|
||||||
> .c-frame-edit {
|
|
||||||
[class*='__handle'] {
|
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.l-layout__frame[s-selected]:not(.is-resizing) {
|
|
||||||
// Show and animate the __move bar for sub-object views with complex content
|
|
||||||
> .c-so-view.has-complex-content {
|
|
||||||
> .c-so-view__local-controls {
|
|
||||||
transition: transform 250ms ease-in-out;
|
|
||||||
transition-delay: $moveBarOutDelay;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover > .c-so-view.has-complex-content {
|
|
||||||
// Move content down so the __move bar doesn't cover it.
|
|
||||||
padding-top: $editFrameMovebarH;
|
|
||||||
transition: $transIn;
|
|
||||||
|
|
||||||
> .c-so-view__local-controls {
|
|
||||||
transition: transform 50ms ease-in-out;
|
|
||||||
transform: translateY($editFrameMovebarH);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.c-so-view--no-frame {
|
|
||||||
// Move content down with a bit more space
|
|
||||||
padding-top: $editFrameMovebarH + $interiorMarginSm;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Show the move bar
|
|
||||||
+ .c-frame-edit .c-frame-edit__move {
|
|
||||||
height: $editFrameMovebarH;
|
|
||||||
transition: $transIn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import LayoutDrag from './../LayoutDrag'
|
import LayoutDrag from './../LayoutDrag'
|
||||||
|
|
||||||
@ -232,21 +181,9 @@
|
|||||||
item: Object,
|
item: Object,
|
||||||
gridSize: Array
|
gridSize: Array
|
||||||
},
|
},
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
dragPosition: undefined,
|
|
||||||
isResizing: undefined
|
|
||||||
}
|
|
||||||
},
|
|
||||||
computed: {
|
computed: {
|
||||||
style() {
|
style() {
|
||||||
let {x, y, width, height} = this.item;
|
let {x, y, width, height} = this.item;
|
||||||
|
|
||||||
if (this.dragPosition) {
|
|
||||||
[x, y] = this.dragPosition.position;
|
|
||||||
[width, height] = this.dragPosition.dimensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
left: (this.gridSize[0] * x) + 'px',
|
left: (this.gridSize[0] * x) + 'px',
|
||||||
top: (this.gridSize[1] * y) + 'px',
|
top: (this.gridSize[1] * y) + 'px',
|
||||||
@ -268,36 +205,40 @@
|
|||||||
return value - this.initialPosition[index];
|
return value - this.initialPosition[index];
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
},
|
||||||
startDrag(posFactor, dimFactor, event, type) {
|
startMove(posFactor, dimFactor, event) {
|
||||||
document.body.addEventListener('mousemove', this.continueDrag);
|
document.body.addEventListener('mousemove', this.continueMove);
|
||||||
document.body.addEventListener('mouseup', this.endDrag);
|
document.body.addEventListener('mouseup', this.endMove);
|
||||||
|
|
||||||
this.dragPosition = {
|
this.dragPosition = {
|
||||||
position: [this.item.x, this.item.y],
|
position: [this.item.x, this.item.y]
|
||||||
dimensions: [this.item.width, this.item.height]
|
|
||||||
};
|
};
|
||||||
this.updatePosition(event);
|
this.updatePosition(event);
|
||||||
this.activeDrag = new LayoutDrag(this.dragPosition, posFactor, dimFactor, this.gridSize);
|
this.activeDrag = new LayoutDrag(this.dragPosition, posFactor, dimFactor, this.gridSize);
|
||||||
this.isResizing = type === 'resize';
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
},
|
},
|
||||||
continueDrag(event) {
|
continueMove(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
this.updatePosition(event);
|
this.updatePosition(event);
|
||||||
this.dragPosition = this.activeDrag.getAdjustedPosition(this.delta);
|
let newPosition = this.activeDrag.getAdjustedPosition(this.delta);
|
||||||
|
|
||||||
|
if (!_.isEqual(newPosition, this.dragPosition)) {
|
||||||
|
this.dragPosition = newPosition;
|
||||||
|
this.$emit('move', this.toGridDelta(this.delta));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
endDrag(event) {
|
endMove(event) {
|
||||||
document.body.removeEventListener('mousemove', this.continueDrag);
|
document.body.removeEventListener('mousemove', this.continueMove);
|
||||||
document.body.removeEventListener('mouseup', this.endDrag);
|
document.body.removeEventListener('mouseup', this.endMove);
|
||||||
this.continueDrag(event);
|
this.continueMove(event);
|
||||||
let [x, y] = this.dragPosition.position;
|
this.$emit('endMove');
|
||||||
let [width, height] = this.dragPosition.dimensions;
|
|
||||||
this.$emit('endDrag', this.item, {x, y, width, height});
|
|
||||||
this.dragPosition = undefined;
|
this.dragPosition = undefined;
|
||||||
this.initialPosition = undefined;
|
this.initialPosition = undefined;
|
||||||
this.delta = undefined;
|
this.delta = undefined;
|
||||||
this.isResizing = undefined;
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
},
|
||||||
|
toGridDelta(pixelDelta) {
|
||||||
|
return pixelDelta.map((v, i) => {
|
||||||
|
return Math.round(v / this.gridSize[i]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,9 +30,9 @@
|
|||||||
</line>
|
</line>
|
||||||
</svg>
|
</svg>
|
||||||
|
|
||||||
<div class="c-frame-edit">
|
|
||||||
<div class="c-frame-edit__move"
|
<div class="c-frame-edit__move"
|
||||||
@mousedown="startDrag($event)"></div>
|
@mousedown="startDrag($event)"></div>
|
||||||
|
<div class="c-frame-edit" v-if="showFrameEdit">
|
||||||
<div class="c-frame-edit__handle"
|
<div class="c-frame-edit__handle"
|
||||||
:class="startHandleClass"
|
:class="startHandleClass"
|
||||||
@mousedown="startDrag($event, 'start')"></div>
|
@mousedown="startDrag($event, 'start')"></div>
|
||||||
@ -66,8 +66,7 @@
|
|||||||
y: 10,
|
y: 10,
|
||||||
x2: 10,
|
x2: 10,
|
||||||
y2: 5,
|
y2: 5,
|
||||||
stroke: '#717171',
|
stroke: '#717171'
|
||||||
useGrid: true
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
@ -76,24 +75,31 @@
|
|||||||
gridSize: Array,
|
gridSize: Array,
|
||||||
initSelect: Boolean,
|
initSelect: Boolean,
|
||||||
index: Number,
|
index: Number,
|
||||||
|
multiSelect: Boolean
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
dragPosition: undefined
|
dragPosition: undefined,
|
||||||
|
dragging: undefined,
|
||||||
|
selection: []
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
showFrameEdit() {
|
||||||
|
let layoutItem = this.selection.length > 0 && this.selection[0][0].context.layoutItem;
|
||||||
|
return !this.multiSelect && layoutItem && layoutItem.id === this.item.id;
|
||||||
|
},
|
||||||
position() {
|
position() {
|
||||||
let {x, y, x2, y2} = this.item;
|
let {x, y, x2, y2} = this.item;
|
||||||
if (this.dragPosition) {
|
if (this.dragging && this.dragPosition) {
|
||||||
({x, y, x2, y2} = this.dragPosition);
|
({x, y, x2, y2} = this.dragPosition);
|
||||||
}
|
}
|
||||||
return {x, y, x2, y2};
|
return {x, y, x2, y2};
|
||||||
},
|
},
|
||||||
style() {
|
style() {
|
||||||
let {x, y, x2, y2} = this.position;
|
let {x, y, x2, y2} = this.position;
|
||||||
let width = this.gridSize[0] * Math.abs(x - x2);
|
let width = Math.max(this.gridSize[0] * Math.abs(x - x2), 1);
|
||||||
let height = this.gridSize[1] * Math.abs(y - y2);
|
let height = Math.max(this.gridSize[1] * Math.abs(y - y2), 1);
|
||||||
let left = this.gridSize[0] * Math.min(x, x2);
|
let left = this.gridSize[0] * Math.min(x, x2);
|
||||||
let top = this.gridSize[1] * Math.min(y, y2);
|
let top = this.gridSize[1] * Math.min(y, y2);
|
||||||
return {
|
return {
|
||||||
@ -175,13 +181,27 @@
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let pxDeltaX = this.startPosition[0] - event.pageX;
|
let pxDeltaX = this.startPosition[0] - event.pageX;
|
||||||
let pxDeltaY = this.startPosition[1] - event.pageY;
|
let pxDeltaY = this.startPosition[1] - event.pageY;
|
||||||
this.dragPosition = this.calculateDragPosition(pxDeltaX, pxDeltaY);
|
let newPosition = this.calculateDragPosition(pxDeltaX, pxDeltaY);
|
||||||
|
|
||||||
|
if (!this.dragging) {
|
||||||
|
if (!_.isEqual(newPosition, this.dragPosition)) {
|
||||||
|
let gridDelta = [event.pageX - this.startPosition[0], event.pageY - this.startPosition[1]];
|
||||||
|
this.dragPosition = newPosition;
|
||||||
|
this.$emit('move', this.toGridDelta(gridDelta));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.dragPosition = newPosition;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
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);
|
||||||
let {x, y, x2, y2} = this.dragPosition;
|
let {x, y, x2, y2} = this.dragPosition;
|
||||||
this.$emit('endDrag', this.item, {x, y, x2, y2});
|
if (!this.dragging) {
|
||||||
|
this.$emit('endMove');
|
||||||
|
} else {
|
||||||
|
this.$emit('endLineResize', this.item, {x, y, x2, y2});
|
||||||
|
}
|
||||||
this.dragPosition = undefined;
|
this.dragPosition = undefined;
|
||||||
this.dragging = undefined;
|
this.dragging = undefined;
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@ -191,6 +211,7 @@
|
|||||||
let gridDeltaY = Math.round(pxDeltaY / this.gridSize[0]); // TODO: should this be gridSize[1]?
|
let gridDeltaY = Math.round(pxDeltaY / this.gridSize[0]); // TODO: should this be gridSize[1]?
|
||||||
let {x, y, x2, y2} = this.item;
|
let {x, y, x2, y2} = this.item;
|
||||||
let dragPosition = {x, y, x2, y2};
|
let dragPosition = {x, y, x2, y2};
|
||||||
|
|
||||||
if (this.dragging === 'start') {
|
if (this.dragging === 'start') {
|
||||||
dragPosition.x -= gridDeltaX;
|
dragPosition.x -= gridDeltaX;
|
||||||
dragPosition.y -= gridDeltaY;
|
dragPosition.y -= gridDeltaY;
|
||||||
@ -205,6 +226,14 @@
|
|||||||
dragPosition.y2 -= gridDeltaY;
|
dragPosition.y2 -= gridDeltaY;
|
||||||
}
|
}
|
||||||
return dragPosition;
|
return dragPosition;
|
||||||
|
},
|
||||||
|
setSelection(selection) {
|
||||||
|
this.selection = selection;
|
||||||
|
},
|
||||||
|
toGridDelta(pixelDelta) {
|
||||||
|
return pixelDelta.map((v, i) => {
|
||||||
|
return Math.round(v / this.gridSize[i]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
@ -217,6 +246,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.openmct.selection.on('change', this.setSelection);
|
||||||
this.context = {
|
this.context = {
|
||||||
layoutItem: this.item,
|
layoutItem: this.item,
|
||||||
index: this.index
|
index: this.index
|
||||||
@ -228,6 +258,7 @@
|
|||||||
if (this.removeSelectable) {
|
if (this.removeSelectable) {
|
||||||
this.removeSelectable();
|
this.removeSelectable();
|
||||||
}
|
}
|
||||||
|
this.openmct.selection.off('change', this.setSelection);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -22,7 +22,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<layout-frame :item="item"
|
<layout-frame :item="item"
|
||||||
:grid-size="gridSize"
|
:grid-size="gridSize"
|
||||||
@endDrag="(item, updates) => $emit('endDrag', item, updates)">
|
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||||
|
@endMove="() => $emit('endMove')">
|
||||||
<object-frame v-if="domainObject"
|
<object-frame v-if="domainObject"
|
||||||
:domain-object="domainObject"
|
:domain-object="domainObject"
|
||||||
:object-path="objectPath"
|
:object-path="objectPath"
|
||||||
@ -66,8 +67,7 @@
|
|||||||
x: position[0],
|
x: position[0],
|
||||||
y: position[1],
|
y: position[1],
|
||||||
identifier: domainObject.identifier,
|
identifier: domainObject.identifier,
|
||||||
hasFrame: hasFrameByDefault(domainObject.type),
|
hasFrame: hasFrameByDefault(domainObject.type)
|
||||||
useGrid: true
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
|
@ -23,7 +23,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<layout-frame :item="item"
|
<layout-frame :item="item"
|
||||||
:grid-size="gridSize"
|
:grid-size="gridSize"
|
||||||
@endDrag="(item, updates) => $emit('endDrag', item, updates)">
|
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||||
|
@endMove="() => $emit('endMove')">
|
||||||
<div class="c-telemetry-view"
|
<div class="c-telemetry-view"
|
||||||
:style="styleObject"
|
:style="styleObject"
|
||||||
v-if="domainObject">
|
v-if="domainObject">
|
||||||
@ -96,10 +97,9 @@
|
|||||||
displayMode: 'all',
|
displayMode: 'all',
|
||||||
value: metadata.getDefaultDisplayValue(),
|
value: metadata.getDefaultDisplayValue(),
|
||||||
stroke: "transparent",
|
stroke: "transparent",
|
||||||
fill: "",
|
fill: "transparent",
|
||||||
color: "",
|
color: "",
|
||||||
size: "13px",
|
size: "13px"
|
||||||
useGrid: true
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
|
@ -23,7 +23,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<layout-frame :item="item"
|
<layout-frame :item="item"
|
||||||
:grid-size="gridSize"
|
:grid-size="gridSize"
|
||||||
@endDrag="(item, updates) => $emit('endDrag', item, updates)">
|
@move="(gridDelta) => $emit('move', gridDelta)"
|
||||||
|
@endMove="() => $emit('endMove')">
|
||||||
<div class="c-text-view"
|
<div class="c-text-view"
|
||||||
:style="style">
|
:style="style">
|
||||||
{{ item.text }}
|
{{ item.text }}
|
||||||
@ -59,8 +60,7 @@
|
|||||||
y: 1,
|
y: 1,
|
||||||
width: 10,
|
width: 10,
|
||||||
height: 5,
|
height: 5,
|
||||||
text: element.text,
|
text: element.text
|
||||||
useGrid: true
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
|
@ -60,6 +60,7 @@ export default function DisplayLayoutPlugin(options) {
|
|||||||
getSelectionContext() {
|
getSelectionContext() {
|
||||||
return {
|
return {
|
||||||
item: domainObject,
|
item: domainObject,
|
||||||
|
supportsMultiSelect: true,
|
||||||
addElement: component && component.$refs.displayLayout.addElement,
|
addElement: component && component.$refs.displayLayout.addElement,
|
||||||
removeItem: component && component.$refs.displayLayout.removeItem,
|
removeItem: component && component.$refs.displayLayout.removeItem,
|
||||||
orderItem: component && component.$refs.displayLayout.orderItem
|
orderItem: component && component.$refs.displayLayout.orderItem
|
||||||
|
@ -33,16 +33,16 @@ define([
|
|||||||
key: 'filters-inspector',
|
key: 'filters-inspector',
|
||||||
name: 'Filters Inspector View',
|
name: 'Filters Inspector View',
|
||||||
canView: function (selection) {
|
canView: function (selection) {
|
||||||
if (selection.length === 0) {
|
if (selection.length === 0 || selection[0].length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let object = selection[0].context.item;
|
let object = selection[0][0].context.item;
|
||||||
|
|
||||||
return object && supportedObjectTypesArray.some(type => object.type === type);
|
return object && supportedObjectTypesArray.some(type => object.type === type);
|
||||||
},
|
},
|
||||||
view: function (selection) {
|
view: function (selection) {
|
||||||
let component;
|
let component;
|
||||||
let providedObject = selection[0].context.item;
|
let providedObject = selection[0][0].context.item;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
show: function (element) {
|
show: function (element) {
|
||||||
@ -59,10 +59,12 @@ define([
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
destroy: function () {
|
destroy: function () {
|
||||||
|
if (component) {
|
||||||
component.$destroy();
|
component.$destroy();
|
||||||
component = undefined;
|
component = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
priority: function () {
|
priority: function () {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -27,16 +27,17 @@ function ToolbarProvider(openmct) {
|
|||||||
key: "flex-layout",
|
key: "flex-layout",
|
||||||
description: "A toolbar for objects inside a Flexible Layout.",
|
description: "A toolbar for objects inside a Flexible Layout.",
|
||||||
forSelection: function (selection) {
|
forSelection: function (selection) {
|
||||||
let context = selection[0].context;
|
let context = selection[0][0].context;
|
||||||
|
|
||||||
return (context && context.type &&
|
return (context && context.type &&
|
||||||
(context.type === 'flexible-layout' || context.type === 'container' || context.type === 'frame'));
|
(context.type === 'flexible-layout' || context.type === 'container' || context.type === 'frame'));
|
||||||
},
|
},
|
||||||
toolbar: function (selection) {
|
toolbar: function (selection) {
|
||||||
|
|
||||||
let primary = selection[0],
|
let selectionPath = selection[0],
|
||||||
secondary = selection[1],
|
primary = selectionPath[0],
|
||||||
tertiary = selection[2],
|
secondary = selectionPath[1],
|
||||||
|
tertiary = selectionPath[2],
|
||||||
deleteFrame,
|
deleteFrame,
|
||||||
toggleContainer,
|
toggleContainer,
|
||||||
deleteContainer,
|
deleteContainer,
|
||||||
@ -46,7 +47,7 @@ function ToolbarProvider(openmct) {
|
|||||||
|
|
||||||
separator = {
|
separator = {
|
||||||
control: "separator",
|
control: "separator",
|
||||||
domainObject: selection[0].context.item,
|
domainObject: primary.context.item,
|
||||||
key: "separator"
|
key: "separator"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -71,7 +71,6 @@ define([
|
|||||||
height: panel.dimensions[1],
|
height: panel.dimensions[1],
|
||||||
x: panel.position[0],
|
x: panel.position[0],
|
||||||
y: panel.position[1],
|
y: panel.position[1],
|
||||||
useGrid: true,
|
|
||||||
identifier: domainObject.identifier,
|
identifier: domainObject.identifier,
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
type: 'telemetry-view',
|
type: 'telemetry-view',
|
||||||
@ -88,7 +87,6 @@ define([
|
|||||||
height: panel.dimensions[1],
|
height: panel.dimensions[1],
|
||||||
x: panel.position[0],
|
x: panel.position[0],
|
||||||
y: panel.position[1],
|
y: panel.position[1],
|
||||||
useGrid: true,
|
|
||||||
identifier: domainObject.identifier,
|
identifier: domainObject.identifier,
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
type: 'subobject-view',
|
type: 'subobject-view',
|
||||||
@ -104,7 +102,7 @@ define([
|
|||||||
return migratedObject;
|
return migratedObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
function migrateFixedPositionConfiguration(elements, telemetryObjects) {
|
function migrateFixedPositionConfiguration(elements, telemetryObjects, gridSize) {
|
||||||
const DEFAULT_STROKE = "transparent";
|
const DEFAULT_STROKE = "transparent";
|
||||||
const DEFAULT_SIZE = "13px";
|
const DEFAULT_SIZE = "13px";
|
||||||
const DEFAULT_COLOR = "";
|
const DEFAULT_COLOR = "";
|
||||||
@ -117,10 +115,16 @@ define([
|
|||||||
y: element.y,
|
y: element.y,
|
||||||
width: element.width,
|
width: element.width,
|
||||||
height: element.height,
|
height: element.height,
|
||||||
useGrid: element.useGrid,
|
|
||||||
id: uuid()
|
id: uuid()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (!element.useGrid) {
|
||||||
|
item.x = Math.round(item.x / gridSize[0]);
|
||||||
|
item.y = Math.round(item.y / gridSize[1]);
|
||||||
|
item.width = Math.round(item.width / gridSize[0]);
|
||||||
|
item.height = Math.round(item.height / gridSize[1]);
|
||||||
|
}
|
||||||
|
|
||||||
if (element.type === "fixed.telemetry") {
|
if (element.type === "fixed.telemetry") {
|
||||||
item.type = "telemetry-view";
|
item.type = "telemetry-view";
|
||||||
item.stroke = element.stroke || DEFAULT_STROKE;
|
item.stroke = element.stroke || DEFAULT_STROKE;
|
||||||
@ -192,10 +196,11 @@ define([
|
|||||||
name: domainObject.name,
|
name: domainObject.name,
|
||||||
type: "layout"
|
type: "layout"
|
||||||
};
|
};
|
||||||
|
let gridSize = domainObject.layoutGrid || DEFAULT_GRID_SIZE;
|
||||||
let layoutType = openmct.types.get('layout');
|
let layoutType = openmct.types.get('layout');
|
||||||
layoutType.definition.initialize(newLayoutObject);
|
layoutType.definition.initialize(newLayoutObject);
|
||||||
newLayoutObject.composition = domainObject.composition;
|
newLayoutObject.composition = domainObject.composition;
|
||||||
newLayoutObject.configuration.layoutGrid = domainObject.layoutGrid || DEFAULT_GRID_SIZE;
|
newLayoutObject.configuration.layoutGrid = gridSize;
|
||||||
|
|
||||||
let elements = domainObject.configuration['fixed-display'].elements;
|
let elements = domainObject.configuration['fixed-display'].elements;
|
||||||
let telemetryObjects = {};
|
let telemetryObjects = {};
|
||||||
@ -211,7 +216,7 @@ define([
|
|||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
.then(function () {
|
.then(function () {
|
||||||
newLayoutObject.configuration.items =
|
newLayoutObject.configuration.items =
|
||||||
migrateFixedPositionConfiguration(elements, telemetryObjects);
|
migrateFixedPositionConfiguration(elements, telemetryObjects, gridSize);
|
||||||
return newLayoutObject;
|
return newLayoutObject;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -37,15 +37,15 @@ define([
|
|||||||
key: 'table-configuration',
|
key: 'table-configuration',
|
||||||
name: 'Telemetry Table Configuration',
|
name: 'Telemetry Table Configuration',
|
||||||
canView: function (selection) {
|
canView: function (selection) {
|
||||||
if (selection.length === 0) {
|
if (selection.length === 0 || selection[0].length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let object = selection[0].context.item;
|
let object = selection[0][0].context.item;
|
||||||
return object && object.type === 'table';
|
return object && object.type === 'table';
|
||||||
},
|
},
|
||||||
view: function (selection) {
|
view: function (selection) {
|
||||||
let component;
|
let component;
|
||||||
let domainObject = selection[0].context.item;
|
let domainObject = selection[0][0].context.item;
|
||||||
let tableConfiguration = new TelemetryTableConfiguration(domainObject, openmct);
|
let tableConfiguration = new TelemetryTableConfiguration(domainObject, openmct);
|
||||||
return {
|
return {
|
||||||
show: function (element) {
|
show: function (element) {
|
||||||
@ -62,8 +62,11 @@ define([
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
destroy: function () {
|
destroy: function () {
|
||||||
|
if (component) {
|
||||||
component.$destroy();
|
component.$destroy();
|
||||||
component = undefined;
|
component = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
tableConfiguration = undefined;
|
tableConfiguration = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,15 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define(['EventEmitter'], function (EventEmitter) {
|
define(
|
||||||
|
[
|
||||||
|
'EventEmitter',
|
||||||
|
'lodash'
|
||||||
|
],
|
||||||
|
function (
|
||||||
|
EventEmitter,
|
||||||
|
_
|
||||||
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages selection state for Open MCT
|
* Manages selection state for Open MCT
|
||||||
@ -47,21 +55,87 @@ define(['EventEmitter'], function (EventEmitter) {
|
|||||||
* Selects the selectable object and emits the 'change' event.
|
* Selects the selectable object and emits the 'change' event.
|
||||||
*
|
*
|
||||||
* @param {object} selectable an object with element and context properties
|
* @param {object} selectable an object with element and context properties
|
||||||
|
* @param {Boolean} isMultiSelectEvent flag indication shift key is pressed or not
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
Selection.prototype.select = function (selectable) {
|
Selection.prototype.select = function (selectable, isMultiSelectEvent) {
|
||||||
if (!Array.isArray(selectable)) {
|
if (!Array.isArray(selectable)) {
|
||||||
selectable = [selectable];
|
selectable = [selectable];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.selected[0] && this.selected[0].element) {
|
let multiSelect = isMultiSelectEvent &&
|
||||||
this.selected[0].element.removeAttribute('s-selected');
|
this.parentSupportsMultiSelect(selectable) &&
|
||||||
|
this.isPeer(selectable) &&
|
||||||
|
!this.selectionContainsParent(selectable);
|
||||||
|
|
||||||
|
if (multiSelect) {
|
||||||
|
this.handleMultiSelect(selectable);
|
||||||
|
} else {
|
||||||
|
this.setSelectionStyles(selectable);
|
||||||
|
this.selected = [selectable];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.selected[1] && this.selected[1].element) {
|
this.emit('change', this.selected);
|
||||||
this.selected[1].element.removeAttribute('s-selected-parent');
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Selection.prototype.handleMultiSelect = function (selectable) {
|
||||||
|
if (this.elementSelected(selectable)) {
|
||||||
|
this.remove(selectable);
|
||||||
|
} else {
|
||||||
|
this.addSelectionAttributes(selectable);
|
||||||
|
this.selected.push(selectable);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Selection.prototype.elementSelected = function (selectable) {
|
||||||
|
return this.selected.some(selectionPath => _.isEqual(selectionPath, selectable));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Selection.prototype.remove = function (selectable) {
|
||||||
|
this.selected = this.selected.filter(selectionPath => !_.isEqual(selectionPath, selectable));
|
||||||
|
|
||||||
|
if (this.selected.length === 0) {
|
||||||
|
this.removeSelectionAttributes(selectable);
|
||||||
|
selectable[1].element.click(); // Select the parent if there is no selection.
|
||||||
|
} else {
|
||||||
|
this.removeSelectionAttributes(selectable, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Selection.prototype.setSelectionStyles = function (selectable) {
|
||||||
|
this.selected.map(selectionPath => {
|
||||||
|
this.removeSelectionAttributes(selectionPath);
|
||||||
|
});
|
||||||
|
this.addSelectionAttributes(selectable);
|
||||||
|
};
|
||||||
|
|
||||||
|
Selection.prototype.removeSelectionAttributes = function (selectionPath, keepParentStyle) {
|
||||||
|
if (selectionPath[0] && selectionPath[0].element) {
|
||||||
|
selectionPath[0].element.removeAttribute('s-selected');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (selectionPath[1] && selectionPath[1].element && !keepParentStyle) {
|
||||||
|
selectionPath[1].element.removeAttribute('s-selected-parent');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Adds selection attributes to the selected element and its parent.
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Selection.prototype.addSelectionAttributes = function (selectable) {
|
||||||
if (selectable[0] && selectable[0].element) {
|
if (selectable[0] && selectable[0].element) {
|
||||||
selectable[0].element.setAttribute('s-selected', "");
|
selectable[0].element.setAttribute('s-selected', "");
|
||||||
}
|
}
|
||||||
@ -69,16 +143,36 @@ define(['EventEmitter'], function (EventEmitter) {
|
|||||||
if (selectable[1] && selectable[1].element) {
|
if (selectable[1] && selectable[1].element) {
|
||||||
selectable[1].element.setAttribute('s-selected-parent', "");
|
selectable[1].element.setAttribute('s-selected-parent', "");
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
this.selected = selectable;
|
/**
|
||||||
this.emit('change', this.selected);
|
* @private
|
||||||
|
*/
|
||||||
|
Selection.prototype.parentSupportsMultiSelect = function (selectable) {
|
||||||
|
return selectable[1] && selectable[1].context.supportsMultiSelect;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Selection.prototype.selectionContainsParent = function (selectable) {
|
||||||
|
return this.selected.some(selectionPath => _.isEqual(selectionPath[0], selectable[1]));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
Selection.prototype.isPeer = function (selectable) {
|
||||||
|
return this.selected.some(selectionPath => _.isEqual(selectionPath[1], selectable[1]));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
Selection.prototype.capture = function (selectable) {
|
Selection.prototype.capture = function (selectable) {
|
||||||
if (!this.capturing) {
|
let capturingContainsSelectable = this.capturing && this.capturing.includes(selectable);
|
||||||
|
|
||||||
|
if (!this.capturing || capturingContainsSelectable) {
|
||||||
this.capturing = [];
|
this.capturing = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,13 +182,14 @@ define(['EventEmitter'], function (EventEmitter) {
|
|||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
Selection.prototype.selectCapture = function (selectable) {
|
Selection.prototype.selectCapture = function (selectable, event) {
|
||||||
if (!this.capturing) {
|
if (!this.capturing) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.select(this.capturing.reverse());
|
let reversedCapturing = this.capturing.reverse();
|
||||||
delete this.capturing;
|
delete this.capturing;
|
||||||
|
this.select(reversedCapturing, event.shiftKey);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -112,7 +207,7 @@ define(['EventEmitter'], function (EventEmitter) {
|
|||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
Selection.prototype.selectable = function (element, context, select) {
|
Selection.prototype.selectable = function (element, context, select) {
|
||||||
var selectable = {
|
let selectable = {
|
||||||
context: context,
|
context: context,
|
||||||
element: element
|
element: element
|
||||||
};
|
};
|
||||||
|
@ -159,8 +159,8 @@ $editFrameBorderHov: 1px solid $editFrameColorHov; // Hover on selectable frames
|
|||||||
$editFrameColorSelected: #ccc; // Border of selected frames
|
$editFrameColorSelected: #ccc; // Border of selected frames
|
||||||
$editFrameColorHandleBg: $colorBodyBg; // Resize handle 'offset' color to make handle standout
|
$editFrameColorHandleBg: $colorBodyBg; // Resize handle 'offset' color to make handle standout
|
||||||
$editFrameColorHandleFg: $editFrameColorSelected; // Resize handle main color
|
$editFrameColorHandleFg: $editFrameColorSelected; // Resize handle main color
|
||||||
$editFrameSelectedShdw: rgba(black, 0.5) 0 1px 10px 1px;
|
$editFrameSelectedShdw: rgba(black, 0.4) 0 1px 5px 1px;
|
||||||
$editFrameSelectedBorder: 1px dashed $editFrameColorSelected; // Selected frame element
|
$editFrameSelectedBorder: 1px solid $editFrameColorHov; // Selected frame element
|
||||||
$editFrameMovebarColorBg: $editFrameColor; // Movebar bg color
|
$editFrameMovebarColorBg: $editFrameColor; // Movebar bg color
|
||||||
$editFrameMovebarColorFg: pullForward($editFrameMovebarColorBg, 20%); // Grippy lines, container size text
|
$editFrameMovebarColorFg: pullForward($editFrameMovebarColorBg, 20%); // Grippy lines, container size text
|
||||||
$editFrameHovMovebarColorBg: pullForward($editFrameMovebarColorBg, 10%); // Hover style
|
$editFrameHovMovebarColorBg: pullForward($editFrameMovebarColorBg, 10%); // Hover style
|
||||||
@ -168,6 +168,7 @@ $editFrameHovMovebarColorFg: pullForward($editFrameMovebarColorFg, 10%);
|
|||||||
$editFrameSelectedMovebarColorBg: pullForward($editFrameMovebarColorBg, 15%); // Selected style
|
$editFrameSelectedMovebarColorBg: pullForward($editFrameMovebarColorBg, 15%); // Selected style
|
||||||
$editFrameSelectedMovebarColorFg: pullForward($editFrameMovebarColorFg, 15%);
|
$editFrameSelectedMovebarColorFg: pullForward($editFrameMovebarColorFg, 15%);
|
||||||
$editFrameMovebarH: 10px; // Height of move bar in layout frame
|
$editFrameMovebarH: 10px; // Height of move bar in layout frame
|
||||||
|
$editMarqueeBorder: 1px dashed $editFrameColorSelected;
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
$colorIconAlias: #4af6f3;
|
$colorIconAlias: #4af6f3;
|
||||||
@ -224,6 +225,8 @@ $menuItemPad: $interiorMargin, floor($interiorMargin * 1.25);
|
|||||||
$paletteItemBorderOuterColorSelected: black;
|
$paletteItemBorderOuterColorSelected: black;
|
||||||
$paletteItemBorderInnerColorSelected: white;
|
$paletteItemBorderInnerColorSelected: white;
|
||||||
$paletteItemBorderInnerColor: rgba($paletteItemBorderOuterColorSelected, 0.3);
|
$paletteItemBorderInnerColor: rgba($paletteItemBorderOuterColorSelected, 0.3);
|
||||||
|
$mixedSettingBg: (transparent rgba($editUIBaseColorHov, 0.7)); // Used in .c-click-icon--mixed
|
||||||
|
$mixedSettingBgSize: 5px;
|
||||||
|
|
||||||
// Forms
|
// Forms
|
||||||
$colorCheck: $colorKey;
|
$colorCheck: $colorKey;
|
||||||
@ -385,8 +388,10 @@ $colorLoadingFg: #776ba2;
|
|||||||
$colorLoadingBg: rgba($colorLoadingFg, 0.1);
|
$colorLoadingBg: rgba($colorLoadingFg, 0.1);
|
||||||
|
|
||||||
// Transitions
|
// Transitions
|
||||||
$transIn: all 50ms ease-in-out;
|
$transInTime: 50ms;
|
||||||
$transOut: all 250ms ease-in-out;
|
$transOutTime: 250ms;
|
||||||
|
$transIn: all $transInTime ease-in-out;
|
||||||
|
$transOut: all $transOutTime ease-in-out;
|
||||||
$transInBounce: all 200ms cubic-bezier(.47,.01,.25,1.5);
|
$transInBounce: all 200ms cubic-bezier(.47,.01,.25,1.5);
|
||||||
$transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3);
|
$transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3);
|
||||||
|
|
||||||
|
@ -163,8 +163,8 @@ $editFrameBorderHov: 1px solid $editFrameColorHov; // Hover on selectable frames
|
|||||||
$editFrameColorSelected: #ccc; // Border of selected frames
|
$editFrameColorSelected: #ccc; // Border of selected frames
|
||||||
$editFrameColorHandleBg: $colorBodyBg; // Resize handle 'offset' color to make handle standout
|
$editFrameColorHandleBg: $colorBodyBg; // Resize handle 'offset' color to make handle standout
|
||||||
$editFrameColorHandleFg: $editFrameColorSelected; // Resize handle main color
|
$editFrameColorHandleFg: $editFrameColorSelected; // Resize handle main color
|
||||||
$editFrameSelectedShdw: rgba(black, 0.5) 0 1px 10px 1px;
|
$editFrameSelectedShdw: rgba(black, 0.4) 0 1px 5px 1px;
|
||||||
$editFrameSelectedBorder: 1px dashed $editFrameColorSelected; // Selected frame element
|
$editFrameSelectedBorder: 1px solid $editFrameColorHov; // Selected frame element
|
||||||
$editFrameMovebarColorBg: $editFrameColor; // Movebar bg color
|
$editFrameMovebarColorBg: $editFrameColor; // Movebar bg color
|
||||||
$editFrameMovebarColorFg: pullForward($editFrameMovebarColorBg, 20%); // Grippy lines, container size text
|
$editFrameMovebarColorFg: pullForward($editFrameMovebarColorBg, 20%); // Grippy lines, container size text
|
||||||
$editFrameHovMovebarColorBg: pullForward($editFrameMovebarColorBg, 10%); // Hover style
|
$editFrameHovMovebarColorBg: pullForward($editFrameMovebarColorBg, 10%); // Hover style
|
||||||
@ -172,6 +172,7 @@ $editFrameHovMovebarColorFg: pullForward($editFrameMovebarColorFg, 10%);
|
|||||||
$editFrameSelectedMovebarColorBg: pullForward($editFrameMovebarColorBg, 15%); // Selected style
|
$editFrameSelectedMovebarColorBg: pullForward($editFrameMovebarColorBg, 15%); // Selected style
|
||||||
$editFrameSelectedMovebarColorFg: pullForward($editFrameMovebarColorFg, 15%);
|
$editFrameSelectedMovebarColorFg: pullForward($editFrameMovebarColorFg, 15%);
|
||||||
$editFrameMovebarH: 10px; // Height of move bar in layout frame
|
$editFrameMovebarH: 10px; // Height of move bar in layout frame
|
||||||
|
$editMarqueeBorder: 1px dashed $editFrameColorSelected;
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
$colorIconAlias: #4af6f3;
|
$colorIconAlias: #4af6f3;
|
||||||
@ -228,6 +229,8 @@ $menuItemPad: $interiorMargin, floor($interiorMargin * 1.25);
|
|||||||
$paletteItemBorderOuterColorSelected: black;
|
$paletteItemBorderOuterColorSelected: black;
|
||||||
$paletteItemBorderInnerColorSelected: white;
|
$paletteItemBorderInnerColorSelected: white;
|
||||||
$paletteItemBorderInnerColor: rgba($paletteItemBorderOuterColorSelected, 0.3);
|
$paletteItemBorderInnerColor: rgba($paletteItemBorderOuterColorSelected, 0.3);
|
||||||
|
$mixedSettingBg: (transparent rgba($editUIBaseColorHov, 0.7)); // Used in .c-click-icon--mixed
|
||||||
|
$mixedSettingBgSize: 5px;
|
||||||
|
|
||||||
// Forms
|
// Forms
|
||||||
$colorCheck: $colorKey;
|
$colorCheck: $colorKey;
|
||||||
@ -389,8 +392,10 @@ $colorLoadingFg: #776ba2;
|
|||||||
$colorLoadingBg: rgba($colorLoadingFg, 0.1);
|
$colorLoadingBg: rgba($colorLoadingFg, 0.1);
|
||||||
|
|
||||||
// Transitions
|
// Transitions
|
||||||
$transIn: all 50ms ease-in-out;
|
$transInTime: 50ms;
|
||||||
$transOut: all 250ms ease-in-out;
|
$transOutTime: 250ms;
|
||||||
|
$transIn: all $transInTime ease-in-out;
|
||||||
|
$transOut: all $transOutTime ease-in-out;
|
||||||
$transInBounce: all 200ms cubic-bezier(.47,.01,.25,1.5);
|
$transInBounce: all 200ms cubic-bezier(.47,.01,.25,1.5);
|
||||||
$transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3);
|
$transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3);
|
||||||
|
|
||||||
|
@ -159,8 +159,8 @@ $editFrameBorderHov: 1px solid $editFrameColorHov; // Hover on selectable frames
|
|||||||
$editFrameColorSelected: #333; // Border of selected frames
|
$editFrameColorSelected: #333; // Border of selected frames
|
||||||
$editFrameColorHandleBg: $colorBodyBg; // Resize handle 'offset' color to make handle standout
|
$editFrameColorHandleBg: $colorBodyBg; // Resize handle 'offset' color to make handle standout
|
||||||
$editFrameColorHandleFg: $editFrameColorSelected; // Resize handle main color
|
$editFrameColorHandleFg: $editFrameColorSelected; // Resize handle main color
|
||||||
$editFrameSelectedShdw: rgba(black, 0.5) 0 1px 10px 1px;
|
$editFrameSelectedShdw: rgba(black, 0.4) 0 1px 5px 1px;
|
||||||
$editFrameSelectedBorder: 1px dashed $editFrameColorSelected; // Selected frame element
|
$editFrameSelectedBorder: 1px solid $editFrameColorHov; // Selected frame element
|
||||||
$editFrameMovebarColorBg: $editFrameColor; // Movebar bg color
|
$editFrameMovebarColorBg: $editFrameColor; // Movebar bg color
|
||||||
$editFrameMovebarColorFg: pullForward($editFrameMovebarColorBg, 20%); // Grippy lines, container size text
|
$editFrameMovebarColorFg: pullForward($editFrameMovebarColorBg, 20%); // Grippy lines, container size text
|
||||||
$editFrameHovMovebarColorBg: pullForward($editFrameMovebarColorBg, 10%); // Hover style
|
$editFrameHovMovebarColorBg: pullForward($editFrameMovebarColorBg, 10%); // Hover style
|
||||||
@ -168,6 +168,7 @@ $editFrameHovMovebarColorFg: pullForward($editFrameMovebarColorFg, 10%);
|
|||||||
$editFrameSelectedMovebarColorBg: pullForward($editFrameMovebarColorBg, 15%); // Selected style
|
$editFrameSelectedMovebarColorBg: pullForward($editFrameMovebarColorBg, 15%); // Selected style
|
||||||
$editFrameSelectedMovebarColorFg: pullForward($editFrameMovebarColorFg, 15%);
|
$editFrameSelectedMovebarColorFg: pullForward($editFrameMovebarColorFg, 15%);
|
||||||
$editFrameMovebarH: 10px; // Height of move bar in layout frame
|
$editFrameMovebarH: 10px; // Height of move bar in layout frame
|
||||||
|
$editMarqueeBorder: 1px dashed $editFrameColorSelected;
|
||||||
|
|
||||||
// Icons
|
// Icons
|
||||||
$colorIconAlias: #4af6f3;
|
$colorIconAlias: #4af6f3;
|
||||||
@ -224,6 +225,8 @@ $menuItemPad: $interiorMargin, floor($interiorMargin * 1.25);
|
|||||||
$paletteItemBorderOuterColorSelected: black;
|
$paletteItemBorderOuterColorSelected: black;
|
||||||
$paletteItemBorderInnerColorSelected: white;
|
$paletteItemBorderInnerColorSelected: white;
|
||||||
$paletteItemBorderInnerColor: rgba($paletteItemBorderOuterColorSelected, 0.3);
|
$paletteItemBorderInnerColor: rgba($paletteItemBorderOuterColorSelected, 0.3);
|
||||||
|
$mixedSettingBg: (transparent rgba($editUIBaseColorHov, 0.9)); // Used in .c-click-icon--mixed
|
||||||
|
$mixedSettingBgSize: 10px;
|
||||||
|
|
||||||
// Forms
|
// Forms
|
||||||
$colorCheck: $colorKey;
|
$colorCheck: $colorKey;
|
||||||
@ -385,8 +388,10 @@ $colorLoadingFg: #776ba2;
|
|||||||
$colorLoadingBg: rgba($colorLoadingFg, 0.1);
|
$colorLoadingBg: rgba($colorLoadingFg, 0.1);
|
||||||
|
|
||||||
// Transitions
|
// Transitions
|
||||||
$transIn: all 50ms ease-in-out;
|
$transInTime: 50ms;
|
||||||
$transOut: all 250ms ease-in-out;
|
$transOutTime: 250ms;
|
||||||
|
$transIn: all $transInTime ease-in-out;
|
||||||
|
$transOut: all $transOutTime ease-in-out;
|
||||||
$transInBounce: all 200ms cubic-bezier(.47,.01,.25,1.5);
|
$transInBounce: all 200ms cubic-bezier(.47,.01,.25,1.5);
|
||||||
$transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3);
|
$transInBounceBig: all 300ms cubic-bezier(.2,1.6,.6,3);
|
||||||
|
|
||||||
|
@ -85,6 +85,15 @@ button {
|
|||||||
margin-left: $interiorMargin;
|
margin-left: $interiorMargin;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$c1: nth($mixedSettingBg, 1);
|
||||||
|
$c2: nth($mixedSettingBg, 2);
|
||||||
|
$mixedBgD: $mixedSettingBgSize $mixedSettingBgSize;
|
||||||
|
|
||||||
|
&--mixed {
|
||||||
|
// E.g. click-icons in toolbar that apply to multiple selected items with different settings
|
||||||
|
@include bgStripes2Color($c1, $c2, $bgSize: $mixedBgD);
|
||||||
|
}
|
||||||
|
|
||||||
&--swatched {
|
&--swatched {
|
||||||
// Color control, show swatch element
|
// Color control, show swatch element
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -93,9 +102,9 @@ button {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
> [class*='swatch'] {
|
> [class*='swatch'] {
|
||||||
box-shadow: inset rgba(black, 0.2) 0 0 1px;
|
box-shadow: inset rgba($editUIBaseColorFg, 0.2) 0 0 0 1px;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
height: 4px;
|
height: 5px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin-top: 1px;
|
margin-top: 1px;
|
||||||
}
|
}
|
||||||
@ -105,6 +114,13 @@ button {
|
|||||||
flex: 1 1 auto;
|
flex: 1 1 auto;
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--mixed {
|
||||||
|
// Styling for swatched buttons when settings are mixed
|
||||||
|
> [class*='swatch'] {
|
||||||
|
@include bgStripes2Color($c1, $c2, $bgSize: $mixedBgD);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,6 +585,10 @@ select {
|
|||||||
margin-left: 2px;
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&__button {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
&__separator {
|
&__separator {
|
||||||
@include cToolbarSeparator();
|
@include cToolbarSeparator();
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@mixin bgStripes($c: yellow, $a: 0.1, $bgsize: 5px, $angle: 90deg) {
|
@mixin bgStripes($c: yellow, $a: 0.1, $bgsize: 5px, $angle: 90deg) {
|
||||||
background-image: linear-gradient($angle,
|
background: linear-gradient($angle,
|
||||||
rgba($c, $a) 25%, transparent 25%,
|
rgba($c, $a) 25%, transparent 25%,
|
||||||
transparent 50%, rgba($c, $a) 50%,
|
transparent 50%, rgba($c, $a) 50%,
|
||||||
rgba($c, $a) 75%, transparent 75%,
|
rgba($c, $a) 75%, transparent 75%,
|
||||||
@ -117,6 +117,16 @@
|
|||||||
background-size: $bgsize $bgsize;
|
background-size: $bgsize $bgsize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin bgStripes2Color($c1, $c2, $bgSize, $angle: -45deg) {
|
||||||
|
background: linear-gradient(-45deg,
|
||||||
|
$c1 0%, $c1 25%,
|
||||||
|
$c2 25%, $c2 50%,
|
||||||
|
$c1 50%, $c1 75%,
|
||||||
|
$c2 75%, $c2 100%
|
||||||
|
) repeat;
|
||||||
|
background-size: $bgSize;
|
||||||
|
}
|
||||||
|
|
||||||
@mixin disabled() {
|
@mixin disabled() {
|
||||||
opacity: $controlDisabledOpacity;
|
opacity: $controlDisabledOpacity;
|
||||||
pointer-events: none !important;
|
pointer-events: none !important;
|
||||||
@ -564,7 +574,6 @@
|
|||||||
@mixin test($c: deeppink, $a: 0.3) {
|
@mixin test($c: deeppink, $a: 0.3) {
|
||||||
background: rgba($c, $a) !important;
|
background: rgba($c, $a) !important;
|
||||||
background-color: rgba($c, $a) !important;
|
background-color: rgba($c, $a) !important;
|
||||||
box-shadow: deeppink 0 0 10px 1px !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@
|
|||||||
|
|
||||||
&__local-controls {
|
&__local-controls {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0; right: 0;
|
top: $interiorMargin; right: $interiorMargin;
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,7 +112,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&.has-complex-content {
|
&.has-complex-content {
|
||||||
.c-so-view__view-large { display: block; }
|
> .c-so-view__view-large { display: block; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************************** OBJECT VIEW */
|
/*************************** OBJECT VIEW */
|
||||||
|
@ -102,7 +102,8 @@ export default {
|
|||||||
this.elements = [];
|
this.elements = [];
|
||||||
this.elementsCache = {};
|
this.elementsCache = {};
|
||||||
this.listeners = [];
|
this.listeners = [];
|
||||||
this.parentObject = selection[0].context.item;
|
this.parentObject = selection && selection[0] && selection[0][0].context.item;
|
||||||
|
|
||||||
if (this.mutationUnobserver) {
|
if (this.mutationUnobserver) {
|
||||||
this.mutationUnobserver();
|
this.mutationUnobserver();
|
||||||
}
|
}
|
||||||
|
@ -199,8 +199,8 @@
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
refreshComposition(selection) {
|
refreshComposition(selection) {
|
||||||
if (selection[0]) {
|
if (selection.length > 0 && selection[0].length > 0) {
|
||||||
let parentObject = selection[0].context.item;
|
let parentObject = selection[0][0].context.item;
|
||||||
|
|
||||||
this.hasComposition = !!(parentObject && this.openmct.composition.get(parentObject));
|
this.hasComposition = !!(parentObject && this.openmct.composition.get(parentObject));
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import _ from 'lodash';
|
|||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
mounted() {
|
mounted() {
|
||||||
this.openmct.selection.on('change', this.updateSelection);
|
this.openmct.selection.on('change', this.updateSelection);
|
||||||
this.updateSelection();
|
this.updateSelection(this.openmct.selection.get());
|
||||||
},
|
},
|
||||||
destroyed() {
|
destroyed() {
|
||||||
this.openmct.selection.off('change', this.updateSelection);
|
this.openmct.selection.off('change', this.updateSelection);
|
||||||
@ -24,12 +24,11 @@ import _ from 'lodash';
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateSelection() {
|
updateSelection(selection) {
|
||||||
let selection = this.openmct.selection.get();
|
if (_.isEqual(this.selection, selection)) {
|
||||||
|
|
||||||
if (_.isEqual(this.selection[0], selection[0])) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.selection = selection;
|
this.selection = selection;
|
||||||
|
|
||||||
if (this.selectedViews) {
|
if (this.selectedViews) {
|
||||||
@ -38,12 +37,14 @@ import _ from 'lodash';
|
|||||||
});
|
});
|
||||||
this.$el.innerHTML = '';
|
this.$el.innerHTML = '';
|
||||||
}
|
}
|
||||||
this.viewContainers = [];
|
|
||||||
|
if (selection.length > 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.selectedViews = this.openmct.inspectorViews.get(selection);
|
this.selectedViews = this.openmct.inspectorViews.get(selection);
|
||||||
this.selectedViews.forEach(selectedView => {
|
this.selectedViews.forEach(selectedView => {
|
||||||
let viewContainer = document.createElement('div');
|
let viewContainer = document.createElement('div');
|
||||||
this.viewContainers.push(viewContainer);
|
|
||||||
|
|
||||||
this.$el.append(viewContainer)
|
this.$el.append(viewContainer)
|
||||||
selectedView.show(viewContainer);
|
selectedView.show(viewContainer);
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="c-properties c-properties--location">
|
<div class="c-properties c-properties--location">
|
||||||
<div class="c-properties__header" title="The location of this linked object.">Original Location</div>
|
<div class="c-properties__header" title="The location of this linked object.">Original Location</div>
|
||||||
<ul class="c-properties__section">
|
<ul class="c-properties__section" v-if="!multiSelect">
|
||||||
<li class="c-properties__row" v-if="originalPath.length">
|
<li class="c-properties__row" v-if="originalPath.length">
|
||||||
<ul class="c-properties__value c-location">
|
<ul class="c-properties__value c-location">
|
||||||
<li v-for="pathObject in orderedOriginalPath"
|
<li v-for="pathObject in orderedOriginalPath"
|
||||||
@ -15,6 +15,7 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<div class="c-properties__row--span-all" v-if="multiSelect">No location to display for multiple items</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -72,6 +73,7 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
domainObject: {},
|
domainObject: {},
|
||||||
|
multiSelect: false,
|
||||||
originalPath: [],
|
originalPath: [],
|
||||||
keyString: ''
|
keyString: ''
|
||||||
}
|
}
|
||||||
@ -106,15 +108,26 @@ export default {
|
|||||||
this.keyString = '';
|
this.keyString = '';
|
||||||
},
|
},
|
||||||
updateSelection(selection) {
|
updateSelection(selection) {
|
||||||
if (!selection.length) {
|
if (!selection.length || !selection[0].length) {
|
||||||
this.clearData();
|
this.clearData();
|
||||||
return;
|
return;
|
||||||
} else if (!selection[0].context.item && selection[1] && selection[1].context.item) {
|
|
||||||
this.setOriginalPath([selection[1].context.item], true);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.domainObject = selection[0].context.item;
|
if (selection.length > 1) {
|
||||||
|
this.multiSelect = true;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
this.multiSelect = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.domainObject = selection[0][0].context.item;
|
||||||
|
let parentObject = selection[0][1];
|
||||||
|
|
||||||
|
if (!this.domainObject && parentObject && parentObject.context.item) {
|
||||||
|
this.setOriginalPath([parentObject.context.item], true);
|
||||||
|
this.keyString = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
let keyString = this.openmct.objects.makeKeyString(this.domainObject.identifier);
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="c-properties c-properties--properties">
|
<div class="c-properties c-properties--properties">
|
||||||
<div class="c-properties__header">Properties</div>
|
<div class="c-properties__header">Properties</div>
|
||||||
<ul class="c-properties__section">
|
<ul class="c-properties__section" v-if="!multiSelect">
|
||||||
<li class="c-properties__row">
|
<li class="c-properties__row">
|
||||||
<div class="c-properties__label">Title</div>
|
<div class="c-properties__label">Title</div>
|
||||||
<div class="c-properties__value">{{ item.name }}</div>
|
<div class="c-properties__value">{{ item.name }}</div>
|
||||||
@ -25,6 +25,7 @@
|
|||||||
<div class="c-properties__value">{{ prop.value }}</div>
|
<div class="c-properties__value">{{ prop.value }}</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
<div class="c-properties__row--span-all" v-if="multiSelect">No properties to display for multiple items</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -35,7 +36,8 @@ export default {
|
|||||||
inject: ['openmct'],
|
inject: ['openmct'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
domainObject: {}
|
domainObject: {},
|
||||||
|
multiSelect: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@ -90,11 +92,19 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
updateSelection(selection) {
|
updateSelection(selection) {
|
||||||
if (selection.length === 0) {
|
if (selection.length === 0 || selection[0].length === 0) {
|
||||||
this.domainObject = {};
|
this.domainObject = {};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.domainObject = selection[0].context.item;
|
|
||||||
|
if (selection.length > 1) {
|
||||||
|
this.multiSelect = true;
|
||||||
|
this.domainObject = {};
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
this.multiSelect = false;
|
||||||
|
this.domainObject = selection[0][0].context.item;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
formatTime(unixTime) {
|
formatTime(unixTime) {
|
||||||
return Moment.utc(unixTime).format('YYYY-MM-DD[\n]HH:mm:ss') + ' UTC';
|
return Moment.utc(unixTime).format('YYYY-MM-DD[\n]HH:mm:ss') + ' UTC';
|
||||||
|
@ -348,7 +348,7 @@
|
|||||||
toggleHasToolbar(selection) {
|
toggleHasToolbar(selection) {
|
||||||
let structure = undefined;
|
let structure = undefined;
|
||||||
|
|
||||||
if (!selection[0]) {
|
if (!selection || !selection[0]) {
|
||||||
structure = [];
|
structure = [];
|
||||||
} else {
|
} else {
|
||||||
structure = this.openmct.toolbars.get(selection);
|
structure = this.openmct.toolbars.get(selection);
|
||||||
|
@ -42,14 +42,13 @@
|
|||||||
this.removeListeners();
|
this.removeListeners();
|
||||||
this.domainObjectsById = {};
|
this.domainObjectsById = {};
|
||||||
|
|
||||||
if (!selection[0]) {
|
if (selection.length === 0 || !selection[0][0]) {
|
||||||
this.structure = [];
|
this.structure = [];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let structure = this.openmct.toolbars.get(selection) || [];
|
let structure = this.openmct.toolbars.get(selection) || [];
|
||||||
this.structure = structure.map(item => {
|
this.structure = structure.map(toolbarItem => {
|
||||||
let toolbarItem = {...item};
|
|
||||||
let domainObject = toolbarItem.domainObject;
|
let domainObject = toolbarItem.domainObject;
|
||||||
let formKeys = [];
|
let formKeys = [];
|
||||||
toolbarItem.control = "toolbar-" + toolbarItem.control;
|
toolbarItem.control = "toolbar-" + toolbarItem.control;
|
||||||
@ -64,12 +63,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (domainObject) {
|
if (domainObject) {
|
||||||
if (formKeys.length > 0) {
|
toolbarItem.value = this.getValue(domainObject, toolbarItem);
|
||||||
toolbarItem.value = this.getFormValue(domainObject, toolbarItem);
|
|
||||||
} else {
|
|
||||||
toolbarItem.value = _.get(domainObject, this.getItemProperty(item));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.registerListener(domainObject);
|
this.registerListener(domainObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,21 +83,12 @@
|
|||||||
observeObject(domainObject, id) {
|
observeObject(domainObject, id) {
|
||||||
let unobserveObject = this.openmct.objects.observe(domainObject, '*', function(newObject) {
|
let unobserveObject = this.openmct.objects.observe(domainObject, '*', function(newObject) {
|
||||||
this.domainObjectsById[id].newObject = JSON.parse(JSON.stringify(newObject));
|
this.domainObjectsById[id].newObject = JSON.parse(JSON.stringify(newObject));
|
||||||
this.scheduleToolbarUpdate();
|
this.updateToolbarAfterMutation();
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
this.unObserveObjects.push(unobserveObject);
|
this.unObserveObjects.push(unobserveObject);
|
||||||
},
|
},
|
||||||
scheduleToolbarUpdate() {
|
|
||||||
if (this.toolbarUpdateScheduled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.toolbarUpdateScheduled = true;
|
|
||||||
setTimeout(this.updateToolbarAfterMutation.bind(this));
|
|
||||||
},
|
|
||||||
updateToolbarAfterMutation() {
|
updateToolbarAfterMutation() {
|
||||||
this.structure = this.structure.map(item => {
|
this.structure = this.structure.map(toolbarItem => {
|
||||||
let toolbarItem = {...item};
|
|
||||||
let domainObject = toolbarItem.domainObject;
|
let domainObject = toolbarItem.domainObject;
|
||||||
|
|
||||||
if (domainObject) {
|
if (domainObject) {
|
||||||
@ -112,12 +97,7 @@
|
|||||||
|
|
||||||
if (newObject) {
|
if (newObject) {
|
||||||
toolbarItem.domainObject = newObject;
|
toolbarItem.domainObject = newObject;
|
||||||
|
toolbarItem.value = this.getValue(newObject, toolbarItem);
|
||||||
if (toolbarItem.formKeys) {
|
|
||||||
toolbarItem.value = this.getFormValue(newObject, toolbarItem);
|
|
||||||
} else {
|
|
||||||
toolbarItem.value = _.get(newObject, this.getItemProperty(item));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,17 +110,58 @@
|
|||||||
delete tracker.newObject;
|
delete tracker.newObject;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.toolbarUpdateScheduled = false;
|
},
|
||||||
|
getValue(domainObject, toolbarItem) {
|
||||||
|
let value = undefined;
|
||||||
|
let applicableSelectedItems = toolbarItem.applicableSelectedItems;
|
||||||
|
|
||||||
|
if (!applicableSelectedItems) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toolbarItem.formKeys) {
|
||||||
|
value = this.getFormValue(domainObject, toolbarItem);
|
||||||
|
} else {
|
||||||
|
let values = [];
|
||||||
|
applicableSelectedItems.forEach(selectionPath => {
|
||||||
|
values.push(_.get(domainObject, this.getItemProperty(toolbarItem, selectionPath)));
|
||||||
|
});
|
||||||
|
|
||||||
|
// If all values are the same, use it, otherwise mark the item as non-specific.
|
||||||
|
if (values.every(value => value === values[0])) {
|
||||||
|
value = values[0];
|
||||||
|
toolbarItem.nonSpecific = false;
|
||||||
|
} else {
|
||||||
|
toolbarItem.nonSpecific = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
},
|
},
|
||||||
getFormValue(domainObject, toolbarItem) {
|
getFormValue(domainObject, toolbarItem) {
|
||||||
let value = {};
|
let value = {};
|
||||||
|
let values = {};
|
||||||
toolbarItem.formKeys.map(key => {
|
toolbarItem.formKeys.map(key => {
|
||||||
value[key] = _.get(domainObject, this.getItemProperty(toolbarItem) + "." + key);
|
values[key] = [];
|
||||||
|
toolbarItem.applicableSelectedItems.forEach(selectionPath => {
|
||||||
|
values[key].push(_.get(domainObject, this.getItemProperty(toolbarItem, selectionPath) + "." + key));
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const key in values) {
|
||||||
|
if (values[key].every(value => value === values[key][0])) {
|
||||||
|
value[key] = values[key][0];
|
||||||
|
toolbarItem.nonSpecific = false;
|
||||||
|
} else {
|
||||||
|
toolbarItem.nonSpecific = true;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
},
|
},
|
||||||
getItemProperty(item) {
|
getItemProperty(item, selectionPath) {
|
||||||
return (typeof item.property === "function") ? item.property() : item.property;
|
return (typeof item.property === "function") ? item.property(selectionPath) : item.property;
|
||||||
},
|
},
|
||||||
removeListeners() {
|
removeListeners() {
|
||||||
if (this.unObserveObjects) {
|
if (this.unObserveObjects) {
|
||||||
@ -152,14 +173,12 @@
|
|||||||
},
|
},
|
||||||
updateObjectValue(value, item) {
|
updateObjectValue(value, item) {
|
||||||
let changedItemId = this.openmct.objects.makeKeyString(item.domainObject.identifier);
|
let changedItemId = this.openmct.objects.makeKeyString(item.domainObject.identifier);
|
||||||
this.structure = this.structure.map((s) => {
|
|
||||||
let toolbarItem = {...s};
|
|
||||||
let domainObject = toolbarItem.domainObject;
|
|
||||||
|
|
||||||
if (domainObject) {
|
this.structure = this.structure.map(toolbarItem => {
|
||||||
let id = this.openmct.objects.makeKeyString(domainObject.identifier);
|
if (toolbarItem.domainObject) {
|
||||||
|
let id = this.openmct.objects.makeKeyString(toolbarItem.domainObject.identifier);
|
||||||
|
|
||||||
if (changedItemId === id && this.getItemProperty(item) === this.getItemProperty(s)) {
|
if (changedItemId === id && _.isEqual(toolbarItem, item)) {
|
||||||
toolbarItem.value = value;
|
toolbarItem.value = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -173,12 +192,17 @@
|
|||||||
this.structure.map(s => {
|
this.structure.map(s => {
|
||||||
if (s.formKeys) {
|
if (s.formKeys) {
|
||||||
s.formKeys.forEach(key => {
|
s.formKeys.forEach(key => {
|
||||||
this.openmct.objects.mutate(item.domainObject, this.getItemProperty(item) + "." + key, value[key]);
|
item.applicableSelectedItems.forEach(selectionPath => {
|
||||||
|
this.openmct.objects.mutate(item.domainObject,
|
||||||
|
this.getItemProperty(item, selectionPath) + "." + key, value[key]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.openmct.objects.mutate(item.domainObject, this.getItemProperty(item), value);
|
item.applicableSelectedItems.forEach(selectionPath => {
|
||||||
|
this.openmct.objects.mutate(item.domainObject, this.getItemProperty(item, selectionPath), value);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
triggerMethod(item, event) {
|
triggerMethod(item, event) {
|
||||||
|
@ -4,14 +4,14 @@
|
|||||||
:title="options.title"
|
:title="options.title"
|
||||||
:class="{
|
:class="{
|
||||||
[options.icon]: true,
|
[options.icon]: true,
|
||||||
'c-icon-button--caution': options.modifier === 'caution'
|
'c-icon-button--caution': options.modifier === 'caution',
|
||||||
|
'c-icon-button--mixed': nonSpecific
|
||||||
}"
|
}"
|
||||||
@click="onClick">
|
@click="onClick">
|
||||||
<div class="c-icon-button__label"
|
<div class="c-icon-button__label"
|
||||||
v-if="options.label">
|
v-if="options.label">
|
||||||
{{ options.label }}
|
{{ options.label }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@ -22,6 +22,11 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
options: Object
|
options: Object
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
nonSpecific() {
|
||||||
|
return this.options.nonSpecific === true;
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
onClick(event) {
|
onClick(event) {
|
||||||
if (this.options.dialog) {
|
if (this.options.dialog) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="c-ctrl-wrapper">
|
<div class="c-ctrl-wrapper">
|
||||||
<div class="c-icon-button c-icon-button--swatched"
|
<div class="c-icon-button c-icon-button--swatched"
|
||||||
:class="options.icon"
|
:class="[options.icon, {'c-icon-button--mixed': nonSpecific}]"
|
||||||
:title="options.title"
|
:title="options.title"
|
||||||
@click="toggle">
|
@click="toggle">
|
||||||
<div class="c-swatch" :style="{
|
<div class="c-swatch" :style="{
|
||||||
@ -36,6 +36,11 @@ export default {
|
|||||||
props: {
|
props: {
|
||||||
options: Object
|
options: Object
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
nonSpecific() {
|
||||||
|
return this.options.nonSpecific === true;
|
||||||
|
}
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
select(color) {
|
select(color) {
|
||||||
if (color.value !== this.options.value) {
|
if (color.value !== this.options.value) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="c-ctrl-wrapper">
|
<div class="c-ctrl-wrapper">
|
||||||
<div class="c-icon-button c-icon-button--menu"
|
<div class="c-icon-button c-icon-button--menu"
|
||||||
:class="options.icon"
|
:class="[options.icon, {'c-click-icon--mixed': nonSpecific}]"
|
||||||
:title="options.title"
|
:title="options.title"
|
||||||
@click="toggle">
|
@click="toggle">
|
||||||
<div class="c-button__label">{{ selectedName }}</div>
|
<div class="c-button__label">{{ selectedName }}</div>
|
||||||
@ -47,7 +47,11 @@ export default {
|
|||||||
if (selectedOption) {
|
if (selectedOption) {
|
||||||
return selectedOption.name || selectedOption.value
|
return selectedOption.name || selectedOption.value
|
||||||
}
|
}
|
||||||
return '';
|
// If no selected option, then options are non-specific
|
||||||
|
return '??px';
|
||||||
|
},
|
||||||
|
nonSpecific() {
|
||||||
|
return this.options.nonSpecific === true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="c-ctrl-wrapper">
|
<div class="c-ctrl-wrapper">
|
||||||
<div class="c-icon-button"
|
<div class="c-icon-button"
|
||||||
:title="nextValue.title"
|
:title="nextValue.title"
|
||||||
:class="nextValue.icon"
|
:class="[nextValue.icon, {'c-click-icon--mixed': nonSpecific}]"
|
||||||
@click="cycle">
|
@click="cycle">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -23,6 +23,9 @@ export default {
|
|||||||
nextIndex = 0;
|
nextIndex = 0;
|
||||||
}
|
}
|
||||||
return this.options.options[nextIndex];
|
return this.options.options[nextIndex];
|
||||||
|
},
|
||||||
|
nonSpecific() {
|
||||||
|
return this.options.nonSpecific === true;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
Reference in New Issue
Block a user