aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNaafiyan Ahmed <naafiyan@gmail.com>2022-04-05 20:03:36 -0400
committerNaafiyan Ahmed <naafiyan@gmail.com>2022-04-05 20:03:36 -0400
commit4823e1c7ceb0e58cdb515e2bb013632d81767ae3 (patch)
treecd5bd1398daaf673b57450883566f473cc480997 /src
parentcb5f0847b098d89a1390acf90579b3c7fbc5ac3e (diff)
added basic grouping when exiting pen mode
Diffstat (limited to 'src')
-rw-r--r--src/Utils.ts1
-rw-r--r--src/client/util/CurrentUserUtils.ts1
-rw-r--r--src/client/views/GestureOverlay.tsx23
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx67
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx3
-rw-r--r--src/client/views/nodes/button/FontIconBox.tsx83
6 files changed, 161 insertions, 17 deletions
diff --git a/src/Utils.ts b/src/Utils.ts
index d0d891f77..6519b5d13 100644
--- a/src/Utils.ts
+++ b/src/Utils.ts
@@ -407,6 +407,7 @@ export function formatTime(time: number) {
return (hours ? hours.toString() + ":" : "") + minutes.toString().padStart(2, '0') + ':' + seconds.toString().padStart(2, '0');
}
+// x is furthest left, y is furthest top, r is furthest right, b is furthest bottom
export function aggregateBounds(boundsList: { x: number, y: number, width?: number, height?: number }[], xpad: number, ypad: number) {
const bounds = boundsList.map(b => ({ x: b.x, y: b.y, r: b.x + (b.width || 0), b: b.y + (b.height || 0) })).reduce((bounds, b) => ({
x: Math.min(b.x, bounds.x), y: Math.min(b.y, bounds.y),
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index c7f293f2c..6cab8c100 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1011,6 +1011,7 @@ export class CurrentUserUtils {
static inkTools(doc: Doc) {
const tools: Button[] = [
{ title: "Pen", toolTip: "Pen (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen", click: 'setActiveInkTool("pen", _readOnly_)' },
+ { title: "Mode", toolTip: "Mode (Ctrl+P)", btnType: ButtonType.ToggleButton, icon: "pen", click: 'setActiveInkTool("write", _readOnly_)' },
{ title: "Eraser", toolTip: "Eraser (Ctrl+E)", btnType: ButtonType.ToggleButton, icon: "eraser", click: 'setActiveInkTool("eraser", _readOnly_)' },
// { title: "Highlighter", toolTip: "Highlighter (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", click: 'setActiveInkTool("highlighter")' },
{ title: "Circle", toolTip: "Circle (Ctrl+Shift+C)", btnType: ButtonType.ToggleButton, icon: "circle", click: 'setActiveInkTool("circle", _readOnly_)' },
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 05e5b7d5f..87b006a93 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -617,22 +617,23 @@ export class GestureOverlay extends Touchable {
newPoints.pop();
const controlPoints: { X: number, Y: number }[] = [];
- // const bezierCurves = fitCurve(newPoints, 10);
- // for (const curve of bezierCurves) {
+ const bezierCurves = fitCurve(newPoints, 10);
+ for (const curve of bezierCurves) {
- // controlPoints.push({ X: curve[0][0], Y: curve[0][1] });
- // controlPoints.push({ X: curve[1][0], Y: curve[1][1] });
- // controlPoints.push({ X: curve[2][0], Y: curve[2][1] });
- // controlPoints.push({ X: curve[3][0], Y: curve[3][1] });
+ controlPoints.push({ X: curve[0][0], Y: curve[0][1] });
+ controlPoints.push({ X: curve[1][0], Y: curve[1][1] });
+ controlPoints.push({ X: curve[2][0], Y: curve[2][1] });
+ controlPoints.push({ X: curve[3][0], Y: curve[3][1] });
- // }
- // const dist = Math.sqrt((controlPoints[0].X - controlPoints.lastElement().X) * (controlPoints[0].X - controlPoints.lastElement().X) +
- // (controlPoints[0].Y - controlPoints.lastElement().Y) * (controlPoints[0].Y - controlPoints.lastElement().Y));
- // if (controlPoints.length > 4 && dist < 10) controlPoints[controlPoints.length - 1] = controlPoints[0];
- // this._points = controlPoints;
+ }
+ const dist = Math.sqrt((controlPoints[0].X - controlPoints.lastElement().X) * (controlPoints[0].X - controlPoints.lastElement().X) +
+ (controlPoints[0].Y - controlPoints.lastElement().Y) * (controlPoints[0].Y - controlPoints.lastElement().Y));
+ if (controlPoints.length > 4 && dist < 10) controlPoints[controlPoints.length - 1] = controlPoints[0];
+ this._points = controlPoints;
this.dispatchGesture(GestureUtils.Gestures.Stroke);
+
}
this._points = [];
}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index e2ea81392..a694ca2b3 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -3,7 +3,7 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction
import { observer } from "mobx-react";
import { computedFn } from "mobx-utils";
import { DateField } from "../../../../fields/DateField";
-import { Doc, HeightSym, Opt, StrListCast, WidthSym } from "../../../../fields/Doc";
+import { Doc, DocListCast, HeightSym, Opt, StrListCast, WidthSym } from "../../../../fields/Doc";
import { Id } from "../../../../fields/FieldSymbols";
import { InkData, InkField, InkTool, PointData, Segment } from "../../../../fields/InkField";
import { List } from "../../../../fields/List";
@@ -17,7 +17,7 @@ import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
import { aggregateBounds, emptyFunction, intersectRect, returnFalse, setupMoveUpEvents, Utils } from "../../../../Utils";
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
import { DocServer } from "../../../DocServer";
-import { Docs, DocUtils } from "../../../documents/Documents";
+import { Docs, DocumentOptions, DocUtils } from "../../../documents/Documents";
import { DocumentType } from "../../../documents/DocumentTypes";
import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
import { DocumentManager } from "../../../util/DocumentManager";
@@ -97,6 +97,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
private _cachedPool: Map<string, PoolData> = new Map();
private _lastTap = 0;
private _batch: UndoManager.Batch | undefined = undefined;
+
+ // private isWritingMode: boolean = true;
+ // private writingModeDocs: Doc[] = [];
private get isAnnotationOverlay() { return this.props.isAnnotationOverlay; }
private get scaleFieldKey() { return this.props.scaleField || "_viewScale"; }
@@ -114,6 +117,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@observable _deleteList: DocumentView[] = [];
@observable _timelineRef = React.createRef<Timeline>();
@observable _marqueeRef = React.createRef<HTMLDivElement>();
+ @observable _marqueeViewRef = React.createRef<MarqueeView>();
@observable _keyframeEditing = false;
@observable ChildDrag: DocumentView | undefined; // child document view being dragged. needed to update drop areas of groups when a group item is dragged.
@@ -432,6 +436,26 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
@action
+ onPenUp = (e: PointerEvent): void => {
+ if (!InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) {
+ document.removeEventListener("pointerup", this.onPenUp);
+ const currentCol = DocListCast(this.rootDoc.currentInkDoc)
+ const rootDocList = DocListCast(this.rootDoc.data);
+ console.log("rootDocList", rootDocList[rootDocList.length - 1]);
+ console.log("currentCol", currentCol);
+ // if (!currentCol[0].data) {
+ // currentCol[0].data = [];
+ // }
+ // let docList = DocListCast(currentCol[0]);
+
+ currentCol.push(rootDocList[rootDocList.length - 1]);
+ console.log(currentCol);
+
+ this._batch?.end();
+ }
+ }
+
+ @action
onPointerDown = (e: React.PointerEvent): void => {
this._downX = this._lastX = e.pageX;
this._downY = this._lastY = e.pageY;
@@ -442,7 +466,32 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
!InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) {
switch (CurrentUserUtils.SelectedTool) {
case InkTool.Highlighter:
- case InkTool.Pen: break; // the GestureOverlay handles ink stroke input -- either as gestures, or drying as ink strokes that are added to document views
+ break;
+ // TODO: nda - this where we want to create the new "writingDoc" collection that we add strokes to
+ case InkTool.Pen:
+ // not the greatest solution
+ // want to have a currentInkDoc field
+ // const freeformOptions: DocumentOptions = {
+ // x: 0,
+ // y: 0,
+ // _width: 1500,
+ // _height: 1000,
+ // _fitWidth: true,
+ // _backgroundColor: 'pink',
+ // _backgroundGridShow: false,
+ // title: `Stroke-Col`,
+ // };
+ // // TODO: nda - fix the null issues that occur here
+ // let currentInkDoc = Docs.Create.FreeformDocument([], freeformOptions)
+ // this.rootDoc.currentInkDoc = currentInkDoc;
+ // // example of creating the list
+ // this.addDocument(currentInkDoc)
+ // // wtf ...
+ // document.addEventListener("pointerup", this.onPenUp);
+
+ // create a new collection
+ // list.push()
+ break; // the GestureOverlay handles ink stroke input -- either as gestures, or drying as ink strokes that are added to document views
case InkTool.Eraser:
document.addEventListener("pointermove", this.onEraserMove);
document.addEventListener("pointerup", this.onEraserUp);
@@ -486,6 +535,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
}
+ public unprocessedDocs: Doc[] =[];
+ public static collectionsWithUnprocessedInk = new Set<CollectionFreeFormView>();
@undoBatch
onGesture = (e: Event, ge: GestureUtils.GestureEvent) => {
switch (ge.gesture) {
@@ -494,7 +545,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const B = this.getTransform().transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height);
const inkDoc = Docs.Create.InkDocument(ActiveInkColor(), CurrentUserUtils.SelectedTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), points,
{ title: "ink stroke", x: B.x - ActiveInkWidth() / 2, y: B.y - ActiveInkWidth() / 2, _width: B.width + ActiveInkWidth(), _height: B.height + ActiveInkWidth() });
- this.addDocument(inkDoc);
+ // const currentInkDoc = Cast(this.dataDoc.currentInkDoc, Doc, null);
+ // if (true) {
+ console.log("doc exists")
+ // Doc.AddDocToList(currentInkDoc.data as Doc, undefined, inkDoc)
+ this.unprocessedDocs.push(inkDoc);
+ CollectionFreeFormView.collectionsWithUnprocessedInk.add(this);
+ this.addDocument(inkDoc);
+ // } else this.addDocument(inkDoc);
e.stopPropagation();
break;
case GestureUtils.Gestures.Box:
@@ -1598,6 +1656,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
TraceMobx();
return <MarqueeView
{...this.props}
+ ref={this._marqueeViewRef}
ungroup={this.props.Document._isGroup ? this.promoteCollection : undefined}
nudge={this.isAnnotationOverlay || this.props.renderDepth > 0 ? undefined : this.nudge}
addDocTab={this.addDocTab}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index b10b0912f..eeb2b653b 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -60,7 +60,9 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@computed get Transform() { return this.props.getTransform(); }
@computed get Bounds() {
+ // nda - ternary argument to transformPoint is returning the lower of the downX/Y and lastX/Y and passing in as args x,y
const topLeft = this.Transform.transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY);
+ // nda - args to transformDirection is just x and y diff btw downX/Y and lastX/Y
const size = this.Transform.transformDirection(this._lastX - this._downX, this._lastY - this._downY);
return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) };
}
@@ -437,6 +439,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
}));
this.props.removeDocument?.(selected);
}
+ // TODO: nda - this is the code to actually get a new grouped collection
const newCollection = this.getCollection(selected, (e as KeyboardEvent)?.key === "t" ? Docs.Create.StackingDocument : undefined, [], group);
this.props.addDocument?.(newCollection);
this.props.selectDocuments([newCollection]);
diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx
index ca13590de..fc0cc87ca 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -5,17 +5,19 @@ import { action, computed, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { ColorState, SketchPicker } from 'react-color';
-import { Doc, StrListCast } from '../../../../fields/Doc';
+import { DataSym, Doc, DocListCast, HeightSym, StrListCast, WidthSym } from '../../../../fields/Doc';
import { InkTool } from '../../../../fields/InkField';
import { createSchema } from '../../../../fields/Schema';
import { ScriptField } from '../../../../fields/ScriptField';
import { BoolCast, Cast, NumCast, ScriptCast, StrCast } from '../../../../fields/Types';
import { WebField } from '../../../../fields/URLField';
-import { Utils } from '../../../../Utils';
+import { aggregateBounds, Utils } from '../../../../Utils';
import { DocumentType } from '../../../documents/DocumentTypes';
+import { DocumentManager } from '../../../util/DocumentManager';
import { ScriptingGlobals } from "../../../util/ScriptingGlobals";
import { SelectionManager } from '../../../util/SelectionManager';
import { undoBatch, UndoManager } from '../../../util/UndoManager';
+import { CollectionFreeFormView } from '../../collections/collectionFreeForm';
import { CollectionViewType } from '../../collections/CollectionView';
import { ContextMenu } from '../../ContextMenu';
import { DocComponent } from '../../DocComponent';
@@ -701,6 +703,80 @@ ScriptingGlobals.add(function toggleItalic(checkResult?: boolean) {
**/
ScriptingGlobals.add(function setActiveInkTool(tool: string, checkResult?: boolean) {
+ // if the global collection has documents
+ // const unallocInk: Doc[] = DocListCast(Doc.UserDoc().unallocatedInkDocs)
+ // if (unallocInk.length) {
+ // get collection freeform view from the ink documents
+ // with that, we can call gesture overlay getCollection on the view
+ // use getDocumentView
+ // You would want to call: DocumentManager.Instance.getDocumentView
+ // const docView = DocumentManager.Instance.getDocumentView(unallocInk[0])
+ // if (docView) {
+ // docView.props.ContainingCollectionView
+ // }
+
+ // easy way without backing up to the server
+ //
+ CollectionFreeFormView.collectionsWithUnprocessedInk.forEach(ffView => {
+ const selected = ffView.unprocessedDocs;
+ ffView._marqueeViewRef.current?.getCollection(ffView.unprocessedDocs, undefined, [], true);
+ // loop through selected an get the bound
+ const bounds: { x: number, y: number, width?: number, height?: number }[] = []
+
+ selected.map(action(d => {
+ const x = NumCast(d.x);
+ const y = NumCast(d.y);
+ const width = d[WidthSym]();
+ const height = d[HeightSym]();
+ bounds.push({x, y, width, height});
+ }))
+
+ const aggregBounds = aggregateBounds(bounds, 0, 0);
+ const marqViewRef = ffView._marqueeViewRef.current;
+
+ // set the vals for bounds in marqueeView
+ if (marqViewRef) {
+ marqViewRef._downX = aggregBounds.x;
+ marqViewRef._downY = aggregBounds.y;
+ marqViewRef._lastX = aggregBounds.r;
+ marqViewRef._lastY = aggregBounds.b;
+ }
+
+ selected.map(action(d => {
+ const dx = NumCast(d.x);
+ const dy = NumCast(d.y);
+ delete d.x;
+ delete d.y;
+ delete d.activeFrame;
+ delete d._timecodeToShow; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
+ delete d._timecodeToHide; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection
+ // TODO: nda - actually calc the bounds
+ // get the bounds
+ // d.x = dx - aggregBounds.x;
+ // d.y = dy - aggregBounds.y;
+
+ // d.x = dx - aggregBounds.x ;
+ // d.y = dy;
+ if (marqViewRef?.Bounds) {
+ d.x = dx - marqViewRef.Bounds.left - marqViewRef.Bounds?.width / 2;
+ d.y = dy - marqViewRef.Bounds.top - marqViewRef.Bounds.height / 2;
+ }
+ console.log(d[DataSym], d.x, d.y)
+ return d;
+ }));
+ ffView.props.removeDocument?.(selected);
+ // TODO: nda - this is the code to actually get a new grouped collection
+ // const newCollection = ffView._marqueeViewRef.current?.getCollection(ffView.unprocessedDocs, undefined, [], true);
+ const newCollection = marqViewRef?.getCollection(selected, undefined, [], true);
+ console.log("newcoll:", newCollection?.[DataSym]);
+
+ // nda - bug: when deleting a stroke before leaving writing mode, delete the stroke from unprocessed ink docs
+ newCollection && ffView.props.addDocument?.(newCollection);
+ ffView.unprocessedDocs = [];
+ });
+
+ CollectionFreeFormView.collectionsWithUnprocessedInk.clear();
+
if (checkResult) {
return ((Doc.UserDoc().activeInkTool === tool && !GestureOverlay.Instance?.InkShape) || GestureOverlay.Instance?.InkShape === tool) ?
Colors.MEDIUM_BLUE : "transparent";
@@ -716,6 +792,9 @@ ScriptingGlobals.add(function setActiveInkTool(tool: string, checkResult?: boole
} else if (tool) { // pen or eraser
if (Doc.UserDoc().activeInkTool === tool && !GestureOverlay.Instance.InkShape) {
Doc.UserDoc().activeInkTool = InkTool.None;
+ } else if (tool == "write") {
+ console.log("write mode selected - create groupDoc here!")
+ //
} else {
Doc.UserDoc().activeInkTool = tool;
GestureOverlay.Instance.InkShape = "";