Files
openmct/src/ui/layout/Layout.vue
Pegah Sarram c6053e234a 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.
2019-04-05 14:22:10 -07:00

362 lines
11 KiB
Vue

<template>
<div class="l-shell" :class="{
'is-editing': isEditing
}">
<div class="l-shell__head">
<CreateButton class="l-shell__create-button"></CreateButton>
<div class="l-shell__controls">
<button class="c-icon-button c-icon-button--major icon-new-window" title="Open in a new browser tab"
@click="openInNewTab"
target="_blank">
</button>
<button v-bind:class="['c-icon-button c-icon-button--major', fullScreen ? 'icon-fullscreen-collapse' : 'icon-fullscreen-expand']"
v-bind:title="`${fullScreen ? 'Exit' : 'Enable'} full screen mode`"
@click="fullScreenToggle">
</button>
</div>
<app-logo></app-logo>
</div>
<multipane class="l-shell__main"
type="horizontal">
<pane class="l-shell__pane-tree"
handle="after"
label="Browse"
collapsable>
<mct-tree class="l-shell__tree"></mct-tree>
</pane>
<pane class="l-shell__pane-main">
<browse-bar class="l-shell__main-view-browse-bar"
ref="browseBar">
</browse-bar>
<toolbar v-if="toolbar" class="l-shell__toolbar"></toolbar>
<object-view class="l-shell__main-container"
ref="browseObject"
:showEditView="true">
</object-view>
<component class="l-shell__time-conductor"
:is="conductorComponent">
</component>
</pane>
<pane class="l-shell__pane-inspector l-pane--holds-multipane"
handle="before"
label="Inspect"
collapsable>
<Inspector :isEditing="isEditing" ref="inspector"></Inspector>
</pane>
</multipane>
<div class="l-shell__status">
<StatusBar></StatusBar>
</div>
</div>
</template>
<style lang="scss">
@import "~styles/sass-base";
/******************************* SHELL */
.l-shell {
position: absolute;
top: 0; right: 0; bottom: 0; left: 0;
display: flex;
flex-flow: column nowrap;
overflow: hidden;
&__status {
background: $colorStatusBarBg;
color: $colorStatusBarFg;
height: 24px;
padding: $interiorMarginSm;
}
&__pane-tree {
width: 40%;
[class*="collapse-button"] {
// For mobile, collapse button becomes menu icon
body.mobile & {
@include cClickIconButton();
position: absolute;
right: -2 * nth($shellPanePad, 2); // Needs to be -1 * when pane is collapsed
top: 0;
transform: translateX(100%);
width: $mobileMenuIconD;
z-index: 2;
&:before {
content: $glyph-icon-menu-hamburger;
}
}
}
}
&__pane-tree,
&__pane-inspector,
&__pane-main {
.l-pane__contents {
display: flex;
flex-flow: column nowrap;
overflow-x: hidden;
> * {
flex: 0 0 auto;
+ * {
margin-top: $interiorMarginLg;
}
}
}
}
body.mobile & {
&__pane-tree {
background: linear-gradient(90deg, transparent 70%, rgba(black, 0.2) 99%, rgba(black, 0.3));
&[class*="--collapsed"] {
[class*="collapse-button"] {
right: -1 * nth($shellPanePad, 2);
}
}
}
}
body.phone.portrait & {
&__pane-tree {
width: calc(100% - #{$mobileMenuIconD + (2 * nth($shellPanePad, 2))});
+ .l-pane {
// Hide pane-main when this pane is expanded
opacity: 0;
pointer-events: none;
}
&[class*="--collapsed"] + .l-pane {
// Show pane-main when tree is collapsed
opacity: 1;
pointer-events: inherit;
transition: opacity 250ms ease 250ms;
}
}
}
&__head,
&__pane-inspector {
body.mobile & {
display: none;
}
}
&__head,
&__status {
flex: 0 0 auto;
display: flex;
}
/******************************* HEAD */
&__main-view-browse-bar {
flex: 0 0 auto;
}
body.mobile & .l-shell__main-view-browse-bar {
margin-left: $mobileMenuIconD; // Make room for the hamburger!
}
&__head {
align-items: center;
background: $colorHeadBg;
justify-content: space-between;
padding: $interiorMargin;
> [class*="__"] + [class*="__"] {
margin-left: $interiorMargin;
}
}
&__create-button,
&__app-logo {
flex: 0 0 auto;
}
&__controls {
flex: 1 1 100%;
display: flex;
justify-content: flex-end;
margin-right: 2.5%;
}
/******************************* MAIN AREA */
&__main-container {
// Wrapper for main views
flex: 1 1 auto !important;
overflow: auto;
}
&__tree {
// Tree component within __pane-tree
flex: 1 1 auto !important;
}
&__time-conductor {
border-top: 1px solid $colorInteriorBorder;
padding-top: $interiorMargin;
}
&__main {
> .l-pane {
padding: nth($shellPanePad, 1) nth($shellPanePad, 2);
}
}
body.desktop & {
&__main {
// Top and bottom padding in container that holds tree, __pane-main and Inspector
padding: $shellMainPad;
min-height: 0;
> .l-pane {
padding-top: 0;
padding-bottom: 0;
}
}
&__pane-tree,
&__pane-inspector {
max-width: 30%;
}
&__pane-tree {
width: 300px;
}
&__pane-inspector {
width: 200px;
}
}
&__toolbar {
$p: $interiorMargin;
background: $editUIBaseColor;
border-radius: $basicCr;
height: $p + 24px; // Need to standardize the height
padding: $p;
}
}
.is-editing {
.l-shell__main-container {
$m: 3px;
box-shadow: $colorBodyBg 0 0 0 1px, $editUIAreaShdw;
margin-left: $m;
margin-right: $m;
&[s-selected] {
// Provide a clearer selection context articulation for the main edit area
box-shadow: $colorBodyBg 0 0 0 1px, $editUIAreaShdwSelected;
}
}
}
</style>
<script>
import Inspector from '../inspector/Inspector.vue';
import MctTree from './mct-tree.vue';
import ObjectView from '../components/ObjectView.vue';
import MctTemplate from '../legacy/mct-template.vue';
import CreateButton from './CreateButton.vue';
import multipane from './multipane.vue';
import pane from './pane.vue';
import BrowseBar from './BrowseBar.vue';
import StatusBar from './status-bar/StatusBar.vue';
import Toolbar from '../toolbar/Toolbar.vue';
import AppLogo from './AppLogo.vue';
var enterFullScreen = () => {
var docElm = document.documentElement;
if (docElm.requestFullscreen) {
docElm.requestFullscreen();
} else if (docElm.mozRequestFullScreen) { /* Firefox */
docElm.mozRequestFullScreen();
} else if (docElm.webkitRequestFullscreen) { /* Chrome, Safari and Opera */
docElm.webkitRequestFullscreen();
} else if (docElm.msRequestFullscreen) { /* IE/Edge */
docElm.msRequestFullscreen();
}
};
var exitFullScreen = () => {
if (document.exitFullscreen) {
document.exitFullscreen();
}
else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
}
else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
}
else if (document.msExitFullscreen) {
document.msExitFullscreen();
}
}
export default {
inject: ['openmct'],
components: {
Inspector,
MctTree,
ObjectView,
'mct-template': MctTemplate,
CreateButton,
multipane,
pane,
BrowseBar,
StatusBar,
Toolbar,
AppLogo
},
mounted() {
this.openmct.editor.on('isEditing', (isEditing)=>{
this.isEditing = isEditing;
});
this.openmct.selection.on('change', this.toggleHasToolbar);
},
data: function () {
return {
fullScreen: false,
conductorComponent: undefined,
isEditing: false,
hasToolbar: false
}
},
computed: {
toolbar() {
return this.hasToolbar && this.isEditing;
}
},
methods: {
fullScreenToggle() {
if (this.fullScreen) {
this.fullScreen = false;
exitFullScreen();
} else {
this.fullScreen = true;
enterFullScreen();
}
},
openInNewTab(event) {
window.open(window.location.href);
},
toggleHasToolbar(selection) {
let structure = undefined;
if (!selection || !selection[0]) {
structure = [];
} else {
structure = this.openmct.toolbars.get(selection);
}
this.hasToolbar = structure.length > 0;
}
}
}
</script>