aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorStanley Yip <stanley_yip@brown.edu>2020-02-08 14:35:20 -0500
committerStanley Yip <stanley_yip@brown.edu>2020-02-08 14:35:20 -0500
commit593016303351f365d6ae13413b72d77495ea6a03 (patch)
tree77e8e48f5fe3e9a9b0a71cfb56f9dd5e9be99e95 /src
parent483aa393cd004e97e2722fea52e920379099cb4d (diff)
syntax highlighting :)
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts1
-rw-r--r--src/client/views/GestureOverlay.tsx22
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx74
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx24
-rw-r--r--src/pen-gestures/GestureUtils.ts2
-rw-r--r--src/pen-gestures/ndollar.ts11
6 files changed, 119 insertions, 15 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 1c13eb079..81a6ff802 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -139,6 +139,7 @@ export interface DocumentOptions {
letterSpacing?: string; // is linear view expanded
flexDirection?: "unset" | "row" | "column" | "row-reverse" | "column-reverse";
selectedIndex?: number;
+ syntaxColor?: string; // can be applied to text for syntax highlighting all matches in the text
}
class EmptyBox {
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index e8262af1b..0b77b4b86 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -50,7 +50,7 @@ export default class GestureOverlay extends Touchable {
@observable private _clipboardDoc?: JSX.Element;
@observable private _possibilities: JSX.Element[] = [];
- @computed private get height(): number { return Math.max(this._pointerY && this._thumbY ? this._thumbY - this._pointerY : 300, 300); }
+ @computed private get height(): number { return 2 * Math.max(this._pointerY && this._thumbY ? this._thumbY - this._pointerY : 300, 300); }
@computed private get showBounds() { return this.Tool !== ToolglassTools.None; }
private _d1: Doc | undefined;
@@ -408,8 +408,8 @@ export default class GestureOverlay extends Touchable {
const points = this._points.map(p => ({ X: p.X - B.left, Y: p.Y - B.top }));
const initialPoint = this._points[0.];
- const xInGlass = initialPoint.X > (this._thumbX ?? Number.MAX_SAFE_INTEGER) && initialPoint.X < (this._thumbX ?? Number.MAX_SAFE_INTEGER) + this.height;
- const yInGlass = initialPoint.Y > (this._thumbY ?? Number.MAX_SAFE_INTEGER) - this.height && initialPoint.Y < (this._thumbY ?? Number.MAX_SAFE_INTEGER);
+ const xInGlass = initialPoint.X > (this._thumbX ?? Number.MAX_SAFE_INTEGER) && initialPoint.X < (this._thumbX ?? Number.MAX_SAFE_INTEGER) + (this.height);
+ const yInGlass = initialPoint.Y > (this._thumbY ?? Number.MAX_SAFE_INTEGER) - (this.height) && initialPoint.Y < (this._thumbY ?? Number.MAX_SAFE_INTEGER);
if (this.Tool !== ToolglassTools.None && xInGlass && yInGlass) {
switch (this.Tool) {
@@ -450,6 +450,14 @@ export default class GestureOverlay extends Touchable {
this.dispatchGesture(GestureUtils.Gestures.Box);
actionPerformed = true;
break;
+ case GestureUtils.Gestures.StartBracket:
+ this.dispatchGesture(GestureUtils.Gestures.StartBracket);
+ actionPerformed = true;
+ break;
+ case GestureUtils.Gestures.EndBracket:
+ this.dispatchGesture(GestureUtils.Gestures.EndBracket);
+ actionPerformed = true;
+ break;
case GestureUtils.Gestures.Line:
actionPerformed = this.handleLineGesture();
break;
@@ -562,8 +570,8 @@ export default class GestureOverlay extends Touchable {
<div className="clipboardDoc-cont" style={{
transform: `translate(${this._thumbX}px, ${(this._thumbY ?? 0) - this.height}px)`,
- height: this.height * 2,
- width: this.height * 2,
+ height: this.height,
+ width: this.height,
pointerEvents: this._clipboardDoc ? "unset" : "none",
touchAction: this._clipboardDoc ? "unset" : "none",
}}>
@@ -571,8 +579,8 @@ export default class GestureOverlay extends Touchable {
</div>
<div className="filter-cont" style={{
transform: `translate(${this._thumbX}px, ${(this._thumbY ?? 0) - this.height}px)`,
- height: this.height * 2,
- width: this.height * 2,
+ height: this.height,
+ width: this.height,
pointerEvents: "none",
touchAction: "none",
display: this.showBounds ? "unset" : "none",
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 2b160f2ff..7b73050ab 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -9,7 +9,7 @@ import { Id } from "../../../../new_fields/FieldSymbols";
import { InkTool, InkField, InkData } from "../../../../new_fields/InkField";
import { createSchema, makeInterface } from "../../../../new_fields/Schema";
import { ScriptField } from "../../../../new_fields/ScriptField";
-import { BoolCast, Cast, DateCast, NumCast, StrCast, ScriptCast } from "../../../../new_fields/Types";
+import { BoolCast, Cast, DateCast, NumCast, StrCast, ScriptCast, FieldValue } from "../../../../new_fields/Types";
import { CurrentUserUtils } from "../../../../server/authentication/models/current_user_utils";
import { aggregateBounds, emptyFunction, intersectRect, returnOne, Utils } from "../../../../Utils";
import { DocServer } from "../../../DocServer";
@@ -42,6 +42,8 @@ import { computedFn } from "mobx-utils";
import { TraceMobx } from "../../../../new_fields/util";
import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
+import { RichTextField } from "../../../../new_fields/RichTextField";
+import { List } from "../../../../new_fields/List";
library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload);
@@ -70,6 +72,9 @@ const PanZoomDocument = makeInterface(panZoomSchema, documentSchema, positionSch
export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
private _lastX: number = 0;
private _lastY: number = 0;
+ private _inkToTextStartX: number | undefined;
+ private _inkToTextStartY: number | undefined;
+ private _wordPalette: Map<string, string> = new Map<string, string>();
private _clusterDistance: number = 75;
private _hitCluster = false;
private _layoutComputeReaction: IReactionDisposer | undefined;
@@ -411,11 +416,78 @@ export class CollectionFreeFormView extends CollectionSubView(PanZoomDocument) {
});
this.addDocument(Docs.Create.FreeformDocument(sel, { title: "nested collection", x: bounds.x, y: bounds.y, _width: bWidth, _height: bHeight, _panX: 0, _panY: 0 }));
sel.forEach(d => this.props.removeDocument(d));
+ e.stopPropagation();
+ break;
+ case GestureUtils.Gestures.StartBracket:
+ const start = this.getTransform().transformPoint(Math.min(...ge.points.map(p => p.X)), Math.min(...ge.points.map(p => p.Y)));
+ this._inkToTextStartX = start[0];
+ this._inkToTextStartY = start[1];
+ console.log("start");
+ break;
+ case GestureUtils.Gestures.EndBracket:
+ console.log("end");
+ if (this._inkToTextStartX && this._inkToTextStartY) {
+ const end = this.getTransform().transformPoint(Math.max(...ge.points.map(p => p.X)), Math.max(...ge.points.map(p => p.Y)));
+ const setDocs = this.getActiveDocuments().filter(s => s.proto?.type === "text" && s.color);
+ const sets = setDocs.map((sd) => {
+ return Cast(sd.data, RichTextField)?.Text as string;
+ });
+ if (sets.length && sets[0]) {
+ this._wordPalette.clear();
+ const colors = setDocs.map(sd => FieldValue(sd.color) as string);
+ sets.forEach((st: string, i: number) => {
+ const words = st.split(",");
+ words.forEach(word => {
+ this._wordPalette.set(word, colors[i]);
+ });
+ });
+ }
+ const inks = this.getActiveDocuments().filter(doc => {
+ if (doc.type === "ink") {
+ const l = NumCast(doc.x);
+ const r = l + doc[WidthSym]();
+ const t = NumCast(doc.y);
+ const b = t + doc[HeightSym]();
+ const pass = !(this._inkToTextStartX! > r || end[0] < l || this._inkToTextStartY! > b || end[1] < t);
+ return pass;
+ }
+ return false;
+ });
+ const inkFields = inks.map(i => Cast(i.data, InkField));
+ CognitiveServices.Inking.Appliers.InterpretStrokes(inkFields.filter(i => i instanceof InkField).map(i => i!.inkData)).then((results) => {
+ const wordResults = results.filter((r: any) => r.category === "inkWord");
+ console.log(wordResults);
+ for (const word of wordResults) {
+ const indices: number[] = word.strokeIds;
+ indices.forEach(i => {
+ const otherInks: Doc[] = [];
+ indices.forEach(i2 => i2 !== i && otherInks.push(inks[i2]));
+ inks[i].relatedInks = new List<Doc>(otherInks);
+ const uniqueColors: string[] = [];
+ Array.from(this._wordPalette.values()).forEach(c => uniqueColors.indexOf(c) === -1 && uniqueColors.push(c));
+ inks[i].alternativeColors = new List<string>(uniqueColors);
+ if (this._wordPalette.has(word.recognizedText)) {
+ inks[i].color = this._wordPalette.get(word.recognizedText);
+ }
+ else {
+ for (const alt of word.alternates) {
+ if (this._wordPalette.has(alt.recognizedString)) {
+ inks[i].color = this._wordPalette.get(alt.recognizedString);
+ break;
+ }
+ }
+ }
+ });
+ }
+ });
+ this._inkToTextStartX = end[0];
+ }
break;
case GestureUtils.Gestures.Text:
if (ge.text) {
const B = this.getTransform().transformPoint(ge.points[0].X, ge.points[0].Y);
this.addDocument(Docs.Create.TextDocument(ge.text, { title: ge.text, x: B[0], y: B[1] }));
+ e.stopPropagation();
}
}
}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 112df8f05..19a71012a 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -20,6 +20,7 @@ import React = require("react");
import MarqueeOptionsMenu from "./MarqueeOptionsMenu";
import { SubCollectionViewProps } from "../CollectionSubView";
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
+import { RichTextField } from "../../../../new_fields/RichTextField";
interface MarqueeViewProps {
getContainerTransform: () => Transform;
@@ -368,18 +369,29 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const selected = this.marqueeSelect(false);
if (e instanceof KeyboardEvent ? e.key === "i" : true) {
const inks = selected.filter(s => s.proto?.type === "ink");
- const sets = selected.filter(s => s.proto?.type === "text")
- const inkFields = inks.map(i => FieldValue(Cast(i.data, InkField)));
+ const setDocs = selected.filter(s => s.proto?.type === "text" && s.color);
+ const sets = setDocs.map((sd) => {
+ return Cast(sd.data, RichTextField)?.Text as string;
+ });
+ const colors = setDocs.map(sd => FieldValue(sd.color) as string);
+ const wordToColor = new Map<string, string>();
+ console.log(sets);
+ sets.forEach((st: string, i: number) => {
+ const words = st.split(",");
+ words.forEach(word => {
+ wordToColor.set(word, colors[i]);
+ });
+ });
+ const inkFields = inks.map(i => Cast(i.data, InkField));
CognitiveServices.Inking.Appliers.InterpretStrokes(inkFields.filter(i => i instanceof InkField).map(i => i!.inkData)).then((results) => {
const wordResults = results.filter((r: any) => r.category === "inkWord");
console.log(wordResults);
for (const word of wordResults) {
const indices: number[] = word.strokeIds;
- const r = Math.floor(Math.random() * 256);
- const g = Math.floor(Math.random() * 256);
- const b = Math.floor(Math.random() * 256);
indices.forEach(i => {
- inks[i].color = `rgb(${r}, ${g}, ${b})`;
+ if (wordToColor.has(word.recognizedText)) {
+ inks[i].color = wordToColor.get(word.recognizedText);
+ }
})
}
});
diff --git a/src/pen-gestures/GestureUtils.ts b/src/pen-gestures/GestureUtils.ts
index 4e3493c1c..f14c573c3 100644
--- a/src/pen-gestures/GestureUtils.ts
+++ b/src/pen-gestures/GestureUtils.ts
@@ -35,6 +35,8 @@ export namespace GestureUtils {
export enum Gestures {
Box = "box",
Line = "line",
+ StartBracket = "startbracket",
+ EndBracket = "endbracket",
Stroke = "stroke",
Scribble = "scribble",
Text = "text"
diff --git a/src/pen-gestures/ndollar.ts b/src/pen-gestures/ndollar.ts
index 9e15ada2d..643d58591 100644
--- a/src/pen-gestures/ndollar.ts
+++ b/src/pen-gestures/ndollar.ts
@@ -142,7 +142,7 @@ export class Result {
//
// NDollarRecognizer constants
//
-const NumMultistrokes = 2;
+const NumMultistrokes = 4;
const NumPoints = 96;
const SquareSize = 250.0;
const OneDThreshold = 0.25; // customize to desired gesture set (usually 0.20 - 0.35)
@@ -178,6 +178,15 @@ export class NDollarRecognizer {
this.Multistrokes[1] = new Multistroke(GestureUtils.Gestures.Line, useBoundedRotationInvariance, new Array(
new Array(new Point(12, 347), new Point(119, 347))
));
+ this.Multistrokes[2] = new Multistroke(GestureUtils.Gestures.StartBracket, useBoundedRotationInvariance, new Array(
+ // new Array(new Point(145, 20), new Point(30, 21), new Point(34, 150))
+ new Array(new Point(31, 25), new Point(145, 20), new Point(31, 25), new Point(34, 150))
+ ));
+ this.Multistrokes[3] = new Multistroke(GestureUtils.Gestures.EndBracket, useBoundedRotationInvariance, new Array(
+ // new Array(new Point(150, 21), new Point(149, 150), new Point(26, 152))
+ // new Array(new Point(150, 150), new Point(150, 0), new Point(150, 150), new Point(0, 150))
+ new Array(new Point(10, 100), new Point(50, 12), new Point(100, 103))
+ ));
//
// PREDEFINED STROKES