diff options
| author | bob <bcz@cs.brown.edu> | 2019-04-30 13:34:30 -0400 |
|---|---|---|
| committer | bob <bcz@cs.brown.edu> | 2019-04-30 13:34:30 -0400 |
| commit | f59503c26b165b71cf3fa6fe4c1b7a14cef2d441 (patch) | |
| tree | e079e726759f5f0e8d08783829860bd05b5f6e99 /src/client/views/collections/collectionFreeForm | |
| parent | e013b7b146f91b0ffbc26e3770f5f90f417da60b (diff) | |
| parent | 86e89178628a27a91665ad835046e536bdb89729 (diff) | |
Merge branch 'master' into newDocs
Diffstat (limited to 'src/client/views/collections/collectionFreeForm')
5 files changed, 73 insertions, 24 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss index 3b2f79be1..3e8a8a442 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.scss @@ -3,4 +3,10 @@ stroke-width: 3; transform: translate(10000px,10000px); pointer-events: all; +} +.collectionfreeformlinkview-linkCircle { + stroke: black; + stroke-width: 3; + transform: translate(10000px,10000px); + pointer-events: all; }
\ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx index d4987fc18..3b700b053 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx @@ -4,20 +4,37 @@ import "./CollectionFreeFormLinkView.scss"; import React = require("react"); import v5 = require("uuid/v5"); import { StrCast, NumCast, BoolCast } from "../../../../new_fields/Types"; -import { Doc } from "../../../../new_fields/Doc"; +import { Doc, WidthSym, HeightSym } from "../../../../new_fields/Doc"; +import { InkingControl } from "../../InkingControl"; export interface CollectionFreeFormLinkViewProps { A: Doc; B: Doc; LinkDocs: Doc[]; + addDocument: (document: Doc, allowDuplicates?: boolean) => boolean; + removeDocument: (document: Doc) => boolean; } @observer export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFormLinkViewProps> { onPointerDown = (e: React.PointerEvent) => { - this.props.LinkDocs.map(l => - console.log("Link:" + StrCast(l.title))); + if (e.button === 0 && !InkingControl.Instance.selectedTool) { + let a = this.props.A; + let b = this.props.B; + let x1 = NumCast(a.x) + (BoolCast(a.isMinimized, false) ? 5 : a[WidthSym]() / 2); + let y1 = NumCast(a.y) + (BoolCast(a.isMinimized, false) ? 5 : a[HeightSym]() / 2); + let x2 = NumCast(b.x) + (BoolCast(b.isMinimized, false) ? 5 : b[WidthSym]() / 2); + let y2 = NumCast(b.y) + (BoolCast(b.isMinimized, false) ? 5 : b[HeightSym]() / 2); + this.props.LinkDocs.map(l => { + let width = l[WidthSym](); + l.x = (x1 + x2) / 2 - width / 2; + l.y = (y1 + y2) / 2 + 10; + if (!this.props.removeDocument(l)) this.props.addDocument(l, false); + }); + e.stopPropagation(); + e.preventDefault(); + } } render() { let l = this.props.LinkDocs; @@ -28,10 +45,14 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo let x2 = NumCast(b.x) + (BoolCast(b.isMinimized, false) ? 5 : NumCast(b.width) / 2); let y2 = NumCast(b.y) + (BoolCast(b.isMinimized, false) ? 5 : NumCast(b.height) / 2); return ( - <line key={Utils.GenerateGuid()} className="collectionfreeformlinkview-linkLine" onPointerDown={this.onPointerDown} - style={{ strokeWidth: `${l.length * 5}` }} - x1={`${x1}`} y1={`${y1}`} - x2={`${x2}`} y2={`${y2}`} /> + <> + <line key={Utils.GenerateGuid()} className="collectionfreeformlinkview-linkLine" + style={{ strokeWidth: `${l.length * 5}` }} + x1={`${x1}`} y1={`${y1}`} + x2={`${x2}`} y2={`${y2}`} /> + <circle key={Utils.GenerateGuid()} className="collectionfreeformlinkview-linkLine" + cx={(x1 + x2) / 2} cy={(y1 + y2) / 2} r={10} onPointerDown={this.onPointerDown} /> + </> ); } }
\ No newline at end of file diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index f693d55e8..e5dcf8c29 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -84,6 +84,14 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP if (containerDoc) { equalViews = DocumentManager.Instance.getDocumentViews(containerDoc.proto!); } + if (view.props.ContainingCollectionView) { + let collid = view.props.ContainingCollectionView.props.Document.Id; + Cast(this.props.Document[this.props.fieldKey], listSpec(Doc), []). + filter(child => + child.Id === collid).map(view => + DocumentManager.Instance.getDocumentViews(view).map(view => + equalViews.push(view))); + } return equalViews.filter(sv => sv.props.ContainingCollectionView && sv.props.ContainingCollectionView.props.Document === this.props.Document); } @@ -107,7 +115,8 @@ export class CollectionFreeFormLinksView extends React.Component<CollectionViewP ); return drawnPairs; }, [] as { a: Doc, b: Doc, l: Doc[] }[]); - return connections.map(c => <CollectionFreeFormLinkView key={Utils.GenerateGuid()} A={c.a} B={c.b} LinkDocs={c.l} />); + return connections.map(c => <CollectionFreeFormLinkView key={Utils.GenerateGuid()} A={c.a} B={c.b} LinkDocs={c.l} + removeDocument={this.props.removeDocument} addDocument={this.props.addDocument} />); } render() { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 2689f48cd..f99800e21 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -24,6 +24,7 @@ import { FieldValue, Cast, NumCast } from "../../../../new_fields/Types"; import { pageSchema } from "../../nodes/ImageBox"; import { List } from "../../../../new_fields/List"; import { Id } from "../../../../new_fields/RefField"; +import { KeyStore } from "../../../../fields/KeyStore"; export const panZoomSchema = createSchema({ panX: "number", @@ -295,7 +296,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY)); } - private childViews = () => [...this.views, <CollectionFreeFormBackgroundView key="backgroundView" {...this.getDocumentViewProps(this.props.Document)} />]; + private childViews = () => [...this.views, <CollectionFreeFormBackgroundView key="backgroundView" {...this.props} {...this.getDocumentViewProps(this.props.Document)} />]; render() { trace(); const containerName = `collectionfreeformview${this.isAnnotationOverlay ? "-overlay" : "-container"}`; @@ -308,7 +309,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { {this.props.Document.Title} </text> </svg> */} - <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} + <MarqueeView container={this} activeDocuments={this.getActiveDocuments} selectDocuments={this.selectDocuments} isSelected={this.props.isSelected} addDocument={this.addDocument} removeDocument={this.props.removeDocument} addLiveTextDocument={this.addLiveTextBox} getContainerTransform={this.getContainerTransform} getTransform={this.getTransform}> <CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY} @@ -320,7 +321,7 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) { </CollectionFreeFormLinksView> {/* <CollectionFreeFormRemoteCursors {...this.props} key="remoteCursors" /> */} </CollectionFreeFormViewPannableContents> - <CollectionFreeFormOverlayView {...this.getDocumentViewProps(this.props.Document)} /> + <CollectionFreeFormOverlayView {...this.getDocumentViewProps(this.props.Document)} {...this.props} /> </MarqueeView> </div> ); @@ -332,7 +333,7 @@ class CollectionFreeFormOverlayView extends React.Component<DocumentViewProps> { @computed get overlayView() { let overlayLayout = Cast(this.props.Document.overlayLayout, "string", ""); return !overlayLayout ? (null) : - (<DocumentContentsView {...this.props} layoutKey={"overlayLayout"} + (<DocumentContentsView {...this.props} layoutKey={KeyStore.OverlayLayout} isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />); } render() { @@ -341,12 +342,12 @@ class CollectionFreeFormOverlayView extends React.Component<DocumentViewProps> { } @observer -class CollectionFreeFormBackgroundView extends React.Component<DocumentViewProps> { +class CollectionFreeFormBackgroundView extends React.Component<DocumentViewProps & { isSelected: () => boolean }> { @computed get backgroundView() { let backgroundLayout = Cast(this.props.Document.backgroundLayout, "string", ""); return !backgroundLayout ? (null) : - (<DocumentContentsView {...this.props} layoutKey={"backgroundLayout"} - isTopMost={this.props.isTopMost} isSelected={returnFalse} select={emptyFunction} />); + (<DocumentContentsView {...this.props} layoutKey={KeyStore.BackgroundLayout} + isTopMost={this.props.isTopMost} isSelected={this.props.isSelected} select={emptyFunction} />); } render() { return this.backgroundView; diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index df1e7a90e..1d3850a72 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -23,6 +23,7 @@ interface MarqueeViewProps { selectDocuments: (docs: Doc[]) => void; removeDocument: (doc: Doc) => boolean; addLiveTextDocument: (doc: Doc) => void; + isSelected: () => boolean; } @observer @@ -33,12 +34,13 @@ export class MarqueeView extends React.Component<MarqueeViewProps> @observable _downX: number = 0; @observable _downY: number = 0; @observable _visible: boolean = false; + _commandExecuted = false; @action cleanupInteractions = (all: boolean = false) => { if (all) { - document.removeEventListener("pointermove", this.onPointerMove, true); document.removeEventListener("pointerup", this.onPointerUp, true); + document.removeEventListener("pointermove", this.onPointerMove, true); } document.removeEventListener("keydown", this.marqueeCommand, true); this._visible = false; @@ -56,6 +58,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> onPointerDown = (e: React.PointerEvent): void => { this._downX = this._lastX = e.pageX; this._downY = this._lastY = e.pageY; + this._commandExecuted = false; PreviewCursor.Visible = false; if ((CollectionFreeFormView.RIGHT_BTN_DRAG && e.button === 0 && !e.altKey && !e.metaKey && this.props.container.props.active()) || (!CollectionFreeFormView.RIGHT_BTN_DRAG && (e.button === 2 || (e.button === 0 && e.altKey)) && this.props.container.props.active())) { @@ -75,7 +78,9 @@ export class MarqueeView extends React.Component<MarqueeViewProps> if (!e.cancelBubble) { if (Math.abs(this._lastX - this._downX) > Utils.DRAG_THRESHOLD || Math.abs(this._lastY - this._downY) > Utils.DRAG_THRESHOLD) { - this._visible = true; + if (!this._commandExecuted) { + this._visible = true; + } e.stopPropagation(); e.preventDefault(); } @@ -104,7 +109,9 @@ export class MarqueeView extends React.Component<MarqueeViewProps> onClick = (e: React.MouseEvent): void => { if (Math.abs(e.clientX - this._downX) < Utils.DRAG_THRESHOLD && Math.abs(e.clientY - this._downY) < Utils.DRAG_THRESHOLD) { - PreviewCursor.Show(e.clientX, e.clientY, this.onKeyPress); + if (this.props.isSelected()) { + PreviewCursor.Show(e.clientX, e.clientY, this.onKeyPress); + } // let the DocumentView stopPropagation of this event when it selects this document } else { // why do we get a click event when the cursor have moved a big distance? // let's cut it off here so no one else has to deal with it. @@ -129,16 +136,21 @@ export class MarqueeView extends React.Component<MarqueeViewProps> @undoBatch @action marqueeCommand = (e: KeyboardEvent) => { - if (e.key === "Backspace" || e.key === "Delete" || e.key === "d") { + if (this._commandExecuted) { + return; + } + if (e.key === "Backspace" || e.key === "Delete" || e.key == "d") { + this._commandExecuted = true; this.marqueeSelect().map(d => this.props.removeDocument(d)); let ink = Cast(this.props.container.props.Document.ink, InkField); if (ink) { this.marqueeInkDelete(ink.inkData); } - this.cleanupInteractions(true); + this.cleanupInteractions(false); e.stopPropagation(); } if (e.key === "c" || e.key === "r" || e.key === "e") { + this._commandExecuted = true; e.stopPropagation(); let bounds = this.Bounds; let selected = this.marqueeSelect().map(d => { @@ -157,7 +169,6 @@ export class MarqueeView extends React.Component<MarqueeViewProps> panX: 0, panY: 0, borderRounding: e.key === "e" ? -1 : undefined, - backgroundColor: selected.length ? "white" : "", scale: zoomBasis, width: bounds.width * zoomBasis, height: bounds.height * zoomBasis, @@ -166,7 +177,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> }); this.marqueeInkDelete(inkData); - SelectionManager.DeselectAll(); + // SelectionManager.DeselectAll(); if (e.key === "r") { let summary = Docs.TextDocument({ x: bounds.left, y: bounds.top, width: 300, height: 100, backgroundColor: "yellow", title: "-summary-" }); Doc.MakeLink(summary.proto!, newCollection.proto!); @@ -176,9 +187,10 @@ export class MarqueeView extends React.Component<MarqueeViewProps> else { this.props.addDocument(newCollection, false); } - this.cleanupInteractions(true); + this.cleanupInteractions(false); } if (e.key === "s") { + this._commandExecuted = true; e.stopPropagation(); e.preventDefault(); let bounds = this.Bounds; @@ -188,7 +200,7 @@ export class MarqueeView extends React.Component<MarqueeViewProps> this.props.addLiveTextDocument(summary); selected.forEach(select => Doc.MakeLink(summary.proto!, select.proto!)); - this.cleanupInteractions(true); + this.cleanupInteractions(false); } } @action |
