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:
Pegah Sarram
2019-04-05 14:22:10 -07:00
committed by Deep Tailor
parent 964c326535
commit c6053e234a
35 changed files with 1519 additions and 769 deletions

View 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>