From 650ca6166548a6ea1554064c98a2927f0450942a Mon Sep 17 00:00:00 2001 From: bobzel Date: Sun, 22 Nov 2020 01:01:33 -0500 Subject: extended clusters to support user groups. made clusters select contents on click. made send to back/ bring to front apply to entire selection. --- src/client/views/ContextMenuItem.tsx | 2 +- src/client/views/GlobalKeyHandler.ts | 11 +++- .../collectionFreeForm/CollectionFreeFormView.tsx | 59 ++++++++++++++-------- .../collections/collectionFreeForm/MarqueeView.tsx | 7 ++- src/client/views/nodes/DocumentView.tsx | 4 +- 5 files changed, 56 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/client/views/ContextMenuItem.tsx b/src/client/views/ContextMenuItem.tsx index d3429cdfb..e63631161 100644 --- a/src/client/views/ContextMenuItem.tsx +++ b/src/client/views/ContextMenuItem.tsx @@ -46,7 +46,7 @@ export class ContextMenuItem extends React.Component KeyControlInfo | Promise; @@ -85,7 +86,15 @@ export class KeyManager { private unmodified = action((keyname: string, e: KeyboardEvent) => { switch (keyname) { - case "a": DragManager.CanEmbed = true; + case "g": + if (document.activeElement?.tagName === "INPUT" || document.activeElement?.tagName === "TEXTAREA") { + return { stopPropagation: false, preventDefault: false }; + } + + const groupings = SelectionManager.SelectedDocuments().slice(); + const randomGroup = random(0, 1000); + UndoManager.RunInBatch(() => groupings.map(dv => dv.layoutDoc.group = randomGroup), "delete"); + SelectionManager.DeselectAll(); break; case " ": // MarqueeView.DragMarquee = !MarqueeView.DragMarquee; // bcz: this needs a better disclosure UI diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 77c29d6ef..f36518439 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -47,6 +47,7 @@ import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); import { CurrentUserUtils } from "../../../util/CurrentUserUtils"; +import { isUndefined } from "lodash"; export const panZoomSchema = createSchema({ _panX: "number", @@ -88,7 +89,7 @@ export class CollectionFreeFormView extends CollectionSubView = new Map(); private _clusterDistance: number = 75; - private _hitCluster = false; + private _hitCluster: number = -1; private _layoutComputeReaction: IReactionDisposer | undefined; private _boundsReaction: IReactionDisposer | undefined; private _layoutPoolData = new ObservableMap(); @@ -288,21 +289,23 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).reduce((cluster, cd) => { - const layoutDoc = Doc.Layout(cd); - const cx = NumCast(cd.x) - this._clusterDistance; - const cy = NumCast(cd.y) - this._clusterDistance; - const cw = NumCast(layoutDoc._width) + 2 * this._clusterDistance; - const ch = NumCast(layoutDoc._height) + 2 * this._clusterDistance; - return !layoutDoc.z && intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 }) ? - NumCast(cd.cluster) : cluster; + const grouping = this.props.Document._useClusters ? NumCast(cd.cluster, -1) : NumCast(cd.group, -1); + if (grouping !== -1) { + const layoutDoc = Doc.Layout(cd); + const cx = NumCast(cd.x) - this._clusterDistance; + const cy = NumCast(cd.y) - this._clusterDistance; + const cw = NumCast(layoutDoc._width) + 2 * this._clusterDistance; + const ch = NumCast(layoutDoc._height) + 2 * this._clusterDistance; + return !layoutDoc.z && intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 }) ? grouping : cluster; + } + return cluster; }, -1); } - tryDragCluster(e: PointerEvent | TouchEvent) { - const ptsParent = e instanceof PointerEvent ? e : e.targetTouches.item(0); - if (ptsParent) { - const cluster = this.pickCluster(this.getTransform().transformPoint(ptsParent.clientX, ptsParent.clientY)); - if (cluster !== -1) { - const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => NumCast(cd.cluster) === cluster); + tryDragCluster(e: PointerEvent | TouchEvent, cluster: number) { + if (cluster !== -1) { + const ptsParent = e instanceof PointerEvent ? e : e.targetTouches.item(0); + if (ptsParent) { + const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.props.Document._useClusters ? NumCast(cd.cluster) : NumCast(cd.group, -1)) === cluster); const clusterDocs = eles.map(ele => DocumentManager.Instance.getDocumentView(ele, this.props.CollectionView)!); const de = new DragManager.DocumentDragData(eles); de.moveDocument = this.props.moveDocument; @@ -405,7 +408,7 @@ export class CollectionFreeFormView extends CollectionSubView !Cast(s.layers, listSpec("string"), []).includes("background")).map(s => clusterColor = StrCast(s.backgroundColor)); set && set.filter(s => Cast(s.layers, listSpec("string"), []).includes("background")).map(s => clusterColor = StrCast(s.backgroundColor)); } - } + } else if (doc && NumCast(doc.group, -1) !== -1) clusterColor = "gray"; return clusterColor; } @@ -415,8 +418,8 @@ export class CollectionFreeFormView extends CollectionSubView this.props.childClickScript || ScriptCast(this.Document.onChildClick); onChildDoubleClickHandler = () => this.props.childDoubleClickScript || ScriptCast(this.Document.onChildDoubleClick); - backgroundHalo = () => BoolCast(this.Document._useClusters); + backgroundHalo = (doc: Doc) => computedFn(() => BoolCast(this.Document._useClusters) || (NumCast(doc.group, -1) !== -1)); parentActive = (outsideReaction: boolean) => this.props.active(outsideReaction) || this.props.parentActive?.(outsideReaction) || this.backgroundActive || this.layoutDoc._viewType === CollectionViewType.Pile ? true : false; getChildDocumentViewProps(childLayout: Doc, childData?: Doc): DocumentViewProps { return { @@ -1014,7 +1017,7 @@ export class CollectionFreeFormView extends CollectionSubView; } + trySelectCluster = (addToSel: boolean) => { + if (this._hitCluster !== -1) { + if (!addToSel) { + SelectionManager.DeselectAll(); + } + const eles = this.childLayoutPairs.map(pair => pair.layout).filter(cd => (this.props.Document._useClusters ? NumCast(cd.cluster) : NumCast(cd.group, -1)) === this._hitCluster); + this.selectDocuments(eles); + return true; + } + return false; + } @computed get marqueeView() { return 0 ? undefined : this.nudge} addDocTab={this.addDocTab} + trySelectCluster={this.trySelectCluster} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} addDocument={this.addDocument} diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 8ed198b4a..0eb05500c 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -34,6 +34,7 @@ interface MarqueeViewProps { selectDocuments: (docs: Doc[]) => void; addLiveTextDocument: (doc: Doc) => void; isSelected: () => boolean; + trySelectCluster: (addToSel: boolean) => boolean; nudge?: (x: number, y: number) => boolean; setPreviewCursor?: (func: (x: number, y: number, drag: boolean) => void) => void; } @@ -299,7 +300,11 @@ export class MarqueeView extends React.Component(Docu const zorders = cm.findByDescription("ZOrder..."); const zorderItems: ContextMenuProps[] = zorders && "subitems" in zorders ? zorders.subitems : []; - zorderItems.push({ description: "Bring to Front", event: () => this.props.bringToFront(this.rootDoc, false), icon: "expand-arrows-alt" }); - zorderItems.push({ description: "Send to Back", event: () => this.props.bringToFront(this.rootDoc, true), icon: "expand-arrows-alt" }); + zorderItems.push({ description: "Bring to Front", event: () => SelectionManager.SelectedDocuments().forEach(dv => dv.props.bringToFront(dv.rootDoc, false)), icon: "expand-arrows-alt" }); + zorderItems.push({ description: "Send to Back", event: () => SelectionManager.SelectedDocuments().forEach(dv => dv.props.bringToFront(dv.rootDoc, true)), icon: "expand-arrows-alt" }); zorderItems.push({ description: this.rootDoc._raiseWhenDragged !== false ? "Keep ZIndex when dragged" : "Allow ZIndex to change when dragged", event: this.toggleRaiseWhenDragged, icon: "expand-arrows-alt" }); !zorders && cm.addItem({ description: "ZOrder...", subitems: zorderItems, icon: "compass" }); -- cgit v1.2.3-70-g09d2