aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoreleanor-park <eleanor_park@brown.edu>2024-07-23 12:07:53 -0400
committereleanor-park <eleanor_park@brown.edu>2024-07-23 12:07:53 -0400
commit3e1ef3d0b5445065ab3f44ffc17bbb04efaa8c8a (patch)
tree54060710007bb52986e86efba0162ffef9142229 /src
parentdb1462bb2ea327a98ca239080e88944425aba768 (diff)
merging w/ zach's branch
Diffstat (limited to 'src')
-rw-r--r--src/.DS_Storebin10244 -> 10244 bytes
-rw-r--r--src/client/documents/DocumentTypes.ts1
-rw-r--r--src/client/util/CurrentUserUtils.ts1
-rw-r--r--src/client/views/DocumentButtonBar.tsx12
-rw-r--r--src/client/views/LightboxView.tsx13
-rw-r--r--src/client/views/MainView.tsx2
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx50
-rw-r--r--src/client/views/smartdraw/AnnotationPalette.tsx370
-rw-r--r--src/client/views/smartdraw/SmartDrawHandler.tsx97
9 files changed, 360 insertions, 186 deletions
diff --git a/src/.DS_Store b/src/.DS_Store
index 75cff7b55..d7a0cd9d4 100644
--- a/src/.DS_Store
+++ b/src/.DS_Store
Binary files differ
diff --git a/src/client/documents/DocumentTypes.ts b/src/client/documents/DocumentTypes.ts
index 8f95068db..03ae2efb7 100644
--- a/src/client/documents/DocumentTypes.ts
+++ b/src/client/documents/DocumentTypes.ts
@@ -26,6 +26,7 @@ export enum DocumentType {
FUNCPLOT = 'funcplot', // function plotter
MAP = 'map',
DATAVIZ = 'dataviz',
+ ANNOPALETTE = 'annopalette',
LOADING = 'loading',
SIMULATION = 'simulation', // physics simulation
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 24a5de42b..fa0cb920d 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -441,6 +441,7 @@ pie title Minerals in my tap water
{ toolTip: "Tap or drag to create a bullet slide", title: "PPT Slide", icon: "person-chalkboard", dragFactory: doc.emptySlide as Doc, clickFactory: DocCast(doc.emptySlide), openFactoryLocation: OpenWhere.overlay, funcs: { hidden: "IsNoviceMode()"}},
{ toolTip: "Tap or drag to create a view slide", title: "View Slide", icon: "address-card", dragFactory: doc.emptyViewSlide as Doc,clickFactory: DocCast(doc.emptyViewSlide),openFactoryLocation: OpenWhere.overlay,funcs: { hidden: "IsNoviceMode()"}},
{ toolTip: "Tap or drag to create a data note", title: "DataNote", icon: "window-maximize",dragFactory: doc.emptyHeader as Doc,clickFactory: DocCast(doc.emptyHeader), openFactoryAsDelegate: true, funcs: { hidden: "IsNoviceMode()"} },
+ { toolTip: "Tap or drag to create an annotation palette",title: "Annotation Palette", icon: "palette", dragFactory: doc.emptyAnnoPalette as Doc, clickFactory: DocCast(doc.emptyAnnoPalette)},
{ toolTip: "Toggle a Calculator REPL", title: "replviewer", icon: "calculator", clickFactory: '<ScriptingRepl />' as any, openFactoryLocation: OpenWhere.overlay}, // hack: clickFactory is not a Doc but will get interpreted as a custom UI by the openDoc() onClick script
// { toolTip: "Toggle an UndoStack", title: "undostacker", icon: "calculator", clickFactory: "<UndoStack />" as any, openFactoryLocation: OpenWhere.overlay},
].map(tuple => (
diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx
index 177546fdc..eb0b00472 100644
--- a/src/client/views/DocumentButtonBar.tsx
+++ b/src/client/views/DocumentButtonBar.tsx
@@ -244,12 +244,14 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (
}
@observable _annoSaved: boolean = false;
- @action
- saveAnno = (targetDoc: Doc) => {
- targetDoc.savedAsAnno = true;
+
+ @undoBatch
+ saveAnno = action((targetDoc: Doc) => {
+ // targetDoc.savedAsAnno = true;
this._annoSaved = true;
- AnnotationPalette.Instance.saveAnno(this.view0, targetDoc);
- };
+ AnnotationPalette.Instance.addToPalette(targetDoc);
+ });
+
@computed
get saveAnnoButton() {
const targetDoc = this.view0?.Document;
diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx
index dcd5a61c7..4fcb7ec9c 100644
--- a/src/client/views/LightboxView.tsx
+++ b/src/client/views/LightboxView.tsx
@@ -24,6 +24,7 @@ import { OpenWhere, OpenWhereMod } from './nodes/OpenWhere';
import { ScriptingGlobals } from '../util/ScriptingGlobals';
import { OverlayView } from './OverlayView';
import { AnnotationPalette } from './smartdraw/AnnotationPalette';
+import { DocData } from '../../fields/DocSymbols';
interface LightboxViewProps {
PanelWidth: number;
@@ -41,7 +42,14 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> {
* @param view
* @returns true if a DocumentView is descendant of the lightbox view
*/
- public static Contains(view?:DocumentView) { return view && LightboxView.Instance?._docView && (view.containerViewPath?.() ?? []).concat(view).includes(LightboxView.Instance?._docView); } // prettier-ignore
+ public static Contains(view?: DocumentView) {
+ return true;
+ }
+ // return (
+ // (view && LightboxView.Instance?._docView && (view.containerViewPath?.() ?? []).concat(view).includes(LightboxView.Instance?._docView)) ||
+ // view?.Document === AnnotationPalette.Instance.FreeformCanvas ||
+ // view?.Document.embedContainer === AnnotationPalette.Instance.DrawingCarousel
+ // ); } // prettier-ignore
public static LightboxDoc = () => LightboxView.Instance?._doc;
// eslint-disable-next-line no-use-before-define
static Instance: LightboxView;
@@ -210,6 +218,7 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> {
togglePalette = () => {
this._showPalette = !this._showPalette;
AnnotationPalette.Instance.displayPalette(this._showPalette);
+ if (this._showPalette === false) AnnotationPalette.Instance.resetPalette(true);
};
togglePen = () => {
Doc.ActiveTool = Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen;
@@ -327,7 +336,7 @@ export class LightboxView extends ObservableReactComponent<LightboxViewProps> {
)}
<LightboxTourBtn lightboxDoc={this.lightboxDoc} navBtn={this.renderNavBtn} future={this.future} stepInto={this.stepInto} />
{toggleBtn('lightboxView-navBtn', 'toggle reading view', this._doc?._layout_fitWidth, 'book-open', 'book', this.toggleFitWidth)}
- {toggleBtn('lightboxView-tabBtn', 'open document in a tab', false, 'file-download', '', this.downloadDoc)}
+ {toggleBtn('lightboxView-tabBtn', 'open document in a tab', false, 'file-export', '', this.downloadDoc)}
{toggleBtn('lightboxView-paletteBtn', 'toggle annotation palette', this._showPalette === true, 'palette', '', this.togglePalette)}
{toggleBtn('lightboxView-penBtn', 'toggle pen annotation', Doc.ActiveTool === InkTool.Pen, 'pen', '', this.togglePen)}
{toggleBtn('lightboxView-exploreBtn', 'toggle navigate only mode', SnappingManager.ExploreMode, 'globe-americas', '', this.toggleExplore)}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 2e7cb1102..d9a8730e4 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -342,6 +342,7 @@ export class MainView extends ObservableReactComponent<{}> {
fa.faTerminal,
fa.faToggleOn,
fa.faFile,
+ fa.faFileExport,
fa.faLocationArrow,
fa.faSearch,
fa.faFileDownload,
@@ -485,6 +486,7 @@ export class MainView extends ObservableReactComponent<{}> {
fa.faAlignJustify,
fa.faCheckSquare,
fa.faSquarePlus,
+ fa.faReply,
fa.faListUl,
fa.faWindowMinimize,
fa.faWindowRestore,
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 3cd1e99ef..d0f65866b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -57,6 +57,7 @@ import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCurso
import './CollectionFreeFormView.scss';
import { MarqueeView } from './MarqueeView';
import { DrawingOptions, SmartDrawHandler } from '../../smartdraw/SmartDrawHandler';
+import { AnnotationPalette } from '../../smartdraw/AnnotationPalette';
@observer
class CollectionFreeFormOverlayView extends React.Component<{ elements: () => ViewDefResult[] }> {
@@ -662,18 +663,19 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
_width: B.width + inkWidth,
_height: B.height + inkWidth,
stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore
- inkWidth,
- ActiveInkColor(),
- ActiveInkBezierApprox(),
- ActiveFillColor(),
- ActiveArrowStart(),
- ActiveArrowEnd(),
- ActiveDash(),
- ActiveIsInkMask()
- );
- });
- newStrokes && this.addDocument?.(newStrokes);
- // setTimeout(() => this._eraserLock--);
+ inkWidth,
+ ActiveInkColor(),
+ ActiveInkBezierApprox(),
+ ActiveFillColor(),
+ ActiveArrowStart(),
+ ActiveArrowEnd(),
+ ActiveDash(),
+ ActiveIsInkMask()
+ );
+ });
+ newStrokes && this.addDocument?.(newStrokes);
+ // setTimeout(() => this._eraserLock--);
+ }
}
});
}
@@ -1284,10 +1286,11 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@undoBatch
createDrawing = (strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => {
this._drawing = [];
- this._drawingContainer = undefined;
+ const xf = this.screenToFreeformContentsXf;
+ // this._drawingContainer = undefined;
strokeData.forEach((stroke: [InkData, string, string]) => {
const bounds = InkField.getBounds(stroke[0]);
- const B = this.screenToFreeformContentsXf.transformBounds(bounds.left, bounds.top, bounds.width, bounds.height);
+ const B = xf.transformBounds(bounds.left, bounds.top, bounds.width, bounds.height);
const inkWidth = ActiveInkWidth() * this.ScreenToLocalBoxXf().Scale;
const inkDoc = Docs.Create.InkDocument(
stroke[0],
@@ -1299,16 +1302,20 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore
inkWidth,
stroke[1],
- undefined,
- stroke[2] === 'none' ? undefined : stroke[2]
+ ActiveInkBezierApprox(),
+ stroke[2] === 'none' ? ActiveFillColor() : stroke[2],
+ ActiveArrowStart(),
+ ActiveArrowEnd(),
+ ActiveDash(),
+ ActiveIsInkMask()
);
this._drawing.push(inkDoc);
this.addDocument(inkDoc);
});
- const collection = this._marqueeViewRef.current?.collection(undefined, true, this._drawing);
+ const collection = containerDoc || this._marqueeViewRef.current?.collection(undefined, true, this._drawing);
if (collection) {
const docData = collection[DocData];
- docData.title = opts.text.match(/^(.*?)~~~.*$/)?.[0] || opts.text;
+ docData.title = opts.text.match(/^(.*?)~~~.*$/)?.[1] || opts.text;
docData.drawingInput = opts.text;
docData.drawingComplexity = opts.complexity;
docData.drawingColored = opts.autoColor;
@@ -1325,10 +1332,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const docData = DocCast(doc[DocData]);
const children = DocListCast(docData.data);
this._props.removeDocument?.(children);
- this._props.removeDocument?.(doc);
+ // this._props.removeDocument?.(doc);
} else {
this._props.removeDocument?.(this._drawing);
- if (this._drawingContainer) this._props.removeDocument?.(this._drawingContainer);
+ // if (this._drawingContainer) this._props.removeDocument?.(this._drawingContainer);
}
};
@@ -2038,8 +2045,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
optionItems.push({
description: 'Show Drawing Editor',
event: action(() => {
- this._showDrawingEditor = !this._showDrawingEditor;
- this._showDrawingEditor ? SmartDrawHandler.Instance.displayRegenerate(this._downX, this._downY - 10, this.createDrawing, this.removeDrawing) : SmartDrawHandler.Instance.hideRegenerate();
+ !SmartDrawHandler.Instance._showRegenerate ? SmartDrawHandler.Instance.displayRegenerate(this._downX, this._downY - 10, this.createDrawing, this.removeDrawing) : SmartDrawHandler.Instance.hideRegenerate();
}),
icon: 'pen-to-square',
});
diff --git a/src/client/views/smartdraw/AnnotationPalette.tsx b/src/client/views/smartdraw/AnnotationPalette.tsx
index 10e88e91e..c8ce9e653 100644
--- a/src/client/views/smartdraw/AnnotationPalette.tsx
+++ b/src/client/views/smartdraw/AnnotationPalette.tsx
@@ -1,49 +1,49 @@
+import { faLaptopHouse } from '@fortawesome/free-solid-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { flexibleCompare } from '@fullcalendar/core/internal';
import { Slider, Switch } from '@mui/material';
import { Button, IconButton } from 'browndash-components';
-import { data } from 'jquery';
import { action, computed, makeObservable, observable } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
import { AiOutlineSend } from 'react-icons/ai';
import ReactLoading from 'react-loading';
import { returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOne, returnTrue, returnZero } from '../../../ClientUtils';
-import { ActiveInkWidth, Doc, StrListCast } from '../../../fields/Doc';
+import { ActiveInkWidth, Doc, DocListCast, StrListCast } from '../../../fields/Doc';
import { DocData } from '../../../fields/DocSymbols';
import { InkData, InkField } from '../../../fields/InkField';
-import { BoolCast, DocCast } from '../../../fields/Types';
-import { emptyFunction } from '../../../Utils';
+import { BoolCast, DocCast, ImageCast, NumCast } from '../../../fields/Types';
+import { emptyFunction, unimplementedFunction } from '../../../Utils';
import { Docs } from '../../documents/Documents';
-import { CollectionViewType } from '../../documents/DocumentTypes';
-import { DragManager } from '../../util/DragManager';
-import { convertDropDataToButtons, makeUserTemplateButton } from '../../util/DropConverter';
+import { makeUserTemplateButton } from '../../util/DropConverter';
import { SettingsManager } from '../../util/SettingsManager';
import { Transform } from '../../util/Transform';
-import { MarqueeOptionsMenu, MarqueeView } from '../collections/collectionFreeForm';
-import { CollectionGridView } from '../collections/collectionGrid';
-import { CollectionStackingView } from '../collections/CollectionStackingView';
-import { DocumentView, DocumentViewInternal } from '../nodes/DocumentView';
-import { FieldViewProps } from '../nodes/FieldView';
+import { undoable, undoBatch } from '../../util/UndoManager';
+import { CollectionFreeFormView, MarqueeOptionsMenu, MarqueeView } from '../collections/collectionFreeForm';
+import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveIsInkMask, DocumentView, DocumentViewInternal } from '../nodes/DocumentView';
+import { FieldView } from '../nodes/FieldView';
import { ObservableReactComponent } from '../ObservableReactComponent';
import { DefaultStyleProvider } from '../StyleProvider';
import './AnnotationPalette.scss';
-import { SmartDrawHandler } from './SmartDrawHandler';
+import { DrawingOptions, SmartDrawHandler } from './SmartDrawHandler';
+import { DocumentType } from '../../documents/DocumentTypes';
+import { ImageField } from '../../../fields/URLField';
+import { CollectionCarousel3DView } from '../collections/CollectionCarousel3DView';
@observer
export class AnnotationPalette extends ObservableReactComponent<{}> {
static Instance: AnnotationPalette;
- @observable private _savedDrawings: Doc[] = [];
- // @observable private _marqueeViewRef = React.createRef<MarqueeView>();
@observable private _display: boolean = false;
@observable private _paletteMode: 'create' | 'view' = 'view';
@observable private _userInput: string = '';
- @observable private _showDrawing: boolean = false;
- @observable private _drawing: Doc | undefined = undefined;
@observable private _isLoading: boolean = false;
- @observable private _detail: number = 5;
- @observable private _size: number = 350;
@observable private _canInteract: boolean = true;
+ @observable private _showRegenerate: boolean = false;
+ @observable private _freeFormCanvas = Docs.Create.FreeformDocument([], {});
+ @observable private _drawingCarousel = Docs.Create.CarouselDocument([], {});
+ @observable private _drawings: Doc[] = [];
+ private _drawing: Doc[] = [];
+ @observable private _opts: DrawingOptions = { text: '', complexity: 5, size: 200, autoColor: true, x: 0, y: 0 };
+ private _gptRes: string[] = [];
constructor(props: any) {
super(props);
@@ -51,40 +51,96 @@ export class AnnotationPalette extends ObservableReactComponent<{}> {
AnnotationPalette.Instance = this;
}
+ public static LayoutString(fieldKey: string) {
+ return FieldView.LayoutString(AnnotationPalette, fieldKey);
+ }
+
+ public get FreeformCanvas() {
+ return this._freeFormCanvas;
+ }
+
+ public get DrawingCarousel() {
+ return this._drawingCarousel;
+ }
+
+ // componentDidUpdate(prevProps: Readonly<{}>) {
+ // const docView = DocumentView.getDocumentView(this._freeFormCanvas);
+ // const componentView = docView?.ComponentView as CollectionFreeFormView;
+ // if (componentView) {
+ // componentView.fitContentOnce();
+ // }
+ // this._freeFormCanvas._freeform_fitContentsToBox = false;
+ // }
+
return170 = () => 170;
@action
+ handleKeyPress = async (event: React.KeyboardEvent) => {
+ if (event.key === 'Enter') {
+ // if (this._showRegenerate) {
+ // this.regenerate();
+ // } else {
+ await this.generateDrawing();
+ // }
+ }
+ };
+
+ @action
setPaletteMode = (mode: 'create' | 'view') => {
this._paletteMode = mode;
};
@action
setUserInput = (input: string) => {
- this._userInput = input;
+ if (!this._isLoading) this._userInput = input;
};
@action
setDetail = (detail: number) => {
- this._detail = detail;
+ if (this._canInteract) this._opts.complexity = detail;
+ };
+
+ @action
+ setColor = (autoColor: boolean) => {
+ if (this._canInteract) this._opts.autoColor = autoColor;
};
@action
setSize = (size: number) => {
- this._size = size;
+ if (this._canInteract) this._opts.size = size;
};
- saveAnno = async (docView: DocumentView | undefined, doc: Doc) => {
- const dragData = new DragManager.DocumentDragData([doc]);
- // convertDropDataToButtons(dragData);
- const clone = await Doc.MakeClone(doc);
- clone.clone.title = doc.title;
- const templateBtn = makeUserTemplateButton(clone.clone);
+ @action
+ resetPalette = (changePaletteMode: boolean) => {
+ if (changePaletteMode) this.setPaletteMode('view');
+ this.setUserInput('');
+ this.setDetail(5);
+ this.setColor(true);
+ this.setSize(200);
+ this._freeFormCanvas = Docs.Create.FreeformDocument([], {});
+ this._drawingCarousel = Docs.Create.CarouselDocument([], {});
+ this._showRegenerate = false;
+ this._canInteract = true;
+ this._drawing = [];
+ this._drawings = [];
+ this._opts = { text: '', complexity: 5, size: 200, autoColor: true, x: 0, y: 0 };
+ this._gptRes = [];
+ };
- // const cloneData: Doc = DocCast(clone.clone[DocData]);
- // cloneData.dragFactory = doc;
- Doc.AddDocToList(Doc.MyAnnos, 'data', templateBtn);
- // const collection = this._marqueeViewRef.current?.collection(undefined, false, this._savedDrawings);
- // if (docView) docView.ComponentView?.removeDocument?.(doc);
+ addToPalette = async (doc: Doc) => {
+ if (!doc.savedAsAnno) {
+ const clone = await Doc.MakeClone(doc);
+ clone.clone.title = doc.title;
+ const image = await this.getIcon(doc);
+ if (image) {
+ const imageDoc = Docs.Create.ImageDocument(image);
+ Doc.AddDocToList(Doc.MyAnnos, 'data', imageDoc);
+ }
+ doc.savedAsAnno = true;
+ // const templateBtn = makeUserTemplateButton(clone.clone);
+ // Doc.AddDocToList(Doc.MyAnnos, 'data', templateBtn);
+ // this.resetPalette(true);
+ }
};
@action
@@ -92,78 +148,136 @@ export class AnnotationPalette extends ObservableReactComponent<{}> {
this._display = display;
};
- @action
- generateDrawing = async () => {
+ @undoBatch
+ generateDrawing = action(async () => {
this._isLoading = true;
- try {
- const drawingRes = await SmartDrawHandler.Instance.drawWithGPT({ X: 0, Y: 0 }, this._userInput);
- const opts = drawingRes?.lastInput;
- const drawing: Doc[] = [];
- drawingRes?.data.forEach((stroke: [InkData, string, string]) => {
- const bounds = InkField.getBounds(stroke[0]);
- // const B = this.screenToFreeformContentsXf.transformBounds(bounds.left, bounds.top, bounds.width, bounds.height);
- const inkWidth = ActiveInkWidth();
- const inkDoc = Docs.Create.InkDocument(
- stroke[0],
- { title: 'stroke',
- // x: B.x - inkWidth / 2,
- // y: B.y - inkWidth / 2,
- // _width: B.width + inkWidth,
- // _height: B.height + inkWidth,
- stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore
- inkWidth,
- stroke[1],
- undefined,
- stroke[2] === 'none' ? undefined : stroke[2]
- );
- drawing.push(inkDoc);
- });
- const collection = MarqueeOptionsMenu.Instance.createCollection(undefined, true, drawing);
- if (collection) {
- const docData = collection[DocData];
- docData.title = opts?.text;
- docData.drawingInput = opts?.text;
- docData.drawingComplexity = opts?.complexity;
- docData.drawingColored = opts?.autoColor;
- docData.drawingSize = opts?.size;
- docData.drawingData = drawingRes?.lastRes;
- this._drawing = collection;
+ this._drawings = [];
+ this._drawing = [];
+ for (var i = 0; i < 3; i++) {
+ try {
+ SmartDrawHandler.Instance._addFunc = this.createDrawing;
+ this._canInteract = false;
+ if (this._showRegenerate) {
+ SmartDrawHandler.Instance._deleteFunc = unimplementedFunction;
+ await SmartDrawHandler.Instance.regenerate(this._opts, this._gptRes[i], this._userInput);
+ } else {
+ await SmartDrawHandler.Instance.drawWithGPT({ X: 0, Y: 0 }, this._userInput, this._opts.complexity, this._opts.size, this._opts.autoColor);
+ }
+ } catch (e) {
+ console.log('Error generating drawing');
}
- this._showDrawing = true;
- } catch (e) {
- console.log('Error generating drawing');
}
+ this._opts.text !== '' ? (this._opts.text = `${this._opts.text} ~~~ ${this._userInput}`) : (this._opts.text = this._userInput);
+ this._userInput = '';
this._isLoading = false;
+ this._showRegenerate = true;
+ });
+
+ @action
+ createDrawing = (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string) => {
+ this._opts = opts;
+ this._gptRes.push(gptRes);
+ this._drawing = [];
+ // const childDocs = DocListCast(this._drawing1[DocData].data);
+ strokeList.forEach((stroke: [InkData, string, string]) => {
+ const bounds = InkField.getBounds(stroke[0]);
+ const inkWidth = ActiveInkWidth();
+ const inkDoc = Docs.Create.InkDocument(
+ stroke[0],
+ { title: 'stroke',
+ x: bounds.left - inkWidth / 2,
+ y: bounds.top - inkWidth / 2,
+ _width: bounds.width + inkWidth,
+ _height: bounds.height + inkWidth,
+ stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore
+ inkWidth,
+ stroke[1],
+ ActiveInkBezierApprox(),
+ stroke[2] === 'none' ? ActiveFillColor() : stroke[2],
+ ActiveArrowStart(),
+ ActiveArrowEnd(),
+ ActiveDash(),
+ ActiveIsInkMask()
+ );
+ this._drawing.push(inkDoc);
+ // childDocs.push(inkDoc);
+ });
+
+ const cv = DocumentView.getDocumentView(this._freeFormCanvas)?.ComponentView as CollectionFreeFormView;
+ const collection = cv._marqueeViewRef.current?.collection(undefined, true, this._drawing);
+ if (collection) {
+ this._drawings.push(collection);
+ cv.fitContentOnce();
+ }
+ this._drawingCarousel = Docs.Create.CarouselDocument(this._drawings, { childLayoutFitWidth: true, _layout_fitWidth: true, _freeform_fitContentsToBox: true });
+ this._freeFormCanvas = Docs.Create.FreeformDocument(this._drawing, { _freeform_fitContentsToBox: true });
};
- // @computed get drawingCreator() {
- // return (
- // MarqueeOptionsMenu.Instance.createCollection(undefined, true, this._drawing);
- // );
- // }
- // return Docs.Create.FreeformDocument([], {});
- // Docs.Create.
- // return (
- // <DocumentView
- // Document={doc}
- // addDocument={undefined}
- // addDocTab={DocumentViewInternal.addDocTabFunc}
- // pinToPres={DocumentView.PinDoc}
- // containerViewPath={returnEmptyDoclist}
- // styleProvider={DefaultStyleProvider}
- // removeDocument={returnFalse}
- // ScreenToLocalTransform={Transform.Identity}
- // PanelWidth={this.return170}
- // PanelHeight={this.return170}
- // renderDepth={0}
- // isContentActive={returnTrue}
- // focus={emptyFunction}
- // whenChildContentsActiveChanged={emptyFunction}
- // childFilters={returnEmptyFilter}
- // childFiltersByRanges={returnEmptyFilter}
- // searchFilterDocs={returnEmptyDoclist}
- // />
- // );
+ saveDrawing = async () => {
+ // const cv = DocumentView.getDocumentView(this._freeFormCanvas)?.ComponentView as CollectionFreeFormView;
+ // if (cv) {
+ // const collection = cv._marqueeViewRef.current?.collection(undefined, true, this._drawing);
+ const cIndex: number = this._drawingCarousel.carousel_index as number;
+ const focusedDrawing = this._drawings[cIndex];
+
+ const docData = focusedDrawing[DocData];
+ docData.title = this._opts.text.match(/^(.*?)~~~.*$/)?.[1] || this._opts.text;
+ docData.drawingInput = this._opts.text;
+ docData.drawingComplexity = this._opts.complexity;
+ docData.drawingColored = this._opts.autoColor;
+ docData.drawingSize = this._opts.size;
+ docData.drawingData = this._gptRes[cIndex];
+ docData.width = this._opts.size;
+ // const image = await this.getIcon(collection);
+ await this.addToPalette(focusedDrawing);
+
+ // if (collection) {
+ // const docData = collection[DocData];
+ // docData.title = this._opts.text.match(/^(.*?)~~~.*$/)?.[1] || this._opts.text;
+ // docData.drawingInput = this._opts.text;
+ // docData.drawingComplexity = this._opts.complexity;
+ // docData.drawingColored = this._opts.autoColor;
+ // docData.drawingSize = this._opts.size;
+ // docData.drawingData = this._gptRes;
+ // docData.width = this._opts.size;
+ // // const image = await this.getIcon(collection);
+ // await this.addToPalette(collection);
+ // }
+ // }
+ };
+
+ async getIcon(group: Doc) {
+ const docView = DocumentView.getDocumentView(group);
+ if (docView) {
+ docView.ComponentView?.updateIcon?.();
+ return new Promise<ImageField | undefined>(res => setTimeout(() => res(ImageCast(docView.Document.icon)), 1000));
+ }
+ return undefined;
+ }
+
+ @computed get drawingCreator() {
+ return (
+ <DocumentView
+ Document={this._freeFormCanvas}
+ addDocument={undefined}
+ addDocTab={DocumentViewInternal.addDocTabFunc}
+ pinToPres={DocumentView.PinDoc}
+ containerViewPath={returnEmptyDoclist}
+ styleProvider={DefaultStyleProvider}
+ removeDocument={returnFalse}
+ ScreenToLocalTransform={Transform.Identity}
+ PanelWidth={this.return170}
+ PanelHeight={this.return170}
+ renderDepth={1}
+ isContentActive={returnTrue}
+ focus={emptyFunction}
+ whenChildContentsActiveChanged={emptyFunction}
+ childFilters={returnEmptyFilter}
+ childFiltersByRanges={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ />
+ );
+ }
render() {
return !this._display ? null : (
@@ -220,13 +334,13 @@ export class AnnotationPalette extends ObservableReactComponent<{}> {
onChange={e => {
this.setUserInput(e.target.value);
}}
- placeholder="Enter item to draw"
- // onKeyDown={this.handleKeyPress}
+ placeholder={this._showRegenerate ? '(Optional) Enter edits' : 'Enter item to draw'}
+ onKeyDown={this.handleKeyPress}
/>
<Button
style={{ alignSelf: 'flex-end' }}
- // text="Send"
- icon={this._isLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <AiOutlineSend />}
+ tooltip={this._showRegenerate ? 'Regenerate' : 'Send'}
+ icon={this._isLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : this._showRegenerate ? <FontAwesomeIcon icon={'rotate'} /> : <AiOutlineSend />}
iconPlacement="right"
color={SettingsManager.userColor}
onClick={this.generateDrawing}
@@ -245,8 +359,9 @@ export class AnnotationPalette extends ObservableReactComponent<{}> {
},
}}
defaultChecked={true}
+ value={this._opts.autoColor}
size="small"
- // onChange={this.setAutoColor}
+ onChange={() => this.setColor(!this._opts.autoColor)}
/>
</div>
<div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', width: '60px' }}>
@@ -271,7 +386,7 @@ export class AnnotationPalette extends ObservableReactComponent<{}> {
max={10}
step={1}
size="small"
- value={this._detail}
+ value={this._opts.complexity}
onChange={(e, val) => {
this.setDetail(val as number);
}}
@@ -297,10 +412,10 @@ export class AnnotationPalette extends ObservableReactComponent<{}> {
}}
style={{ width: '80%' }}
min={50}
- max={700}
+ max={500}
step={10}
size="small"
- value={this._size}
+ value={this._opts.size}
onChange={(e, val) => {
this.setSize(val as number);
}}
@@ -308,9 +423,9 @@ export class AnnotationPalette extends ObservableReactComponent<{}> {
/>
</div>
</div>
- {this._drawing !== undefined && (
+ <div style={{ display: 'none' }}>
<DocumentView
- Document={this._drawing}
+ Document={this._freeFormCanvas}
addDocument={undefined}
addDocTab={DocumentViewInternal.addDocTabFunc}
pinToPres={DocumentView.PinDoc}
@@ -320,7 +435,7 @@ export class AnnotationPalette extends ObservableReactComponent<{}> {
ScreenToLocalTransform={Transform.Identity}
PanelWidth={this.return170}
PanelHeight={this.return170}
- renderDepth={0}
+ renderDepth={1}
isContentActive={returnTrue}
focus={emptyFunction}
whenChildContentsActiveChanged={emptyFunction}
@@ -328,10 +443,41 @@ export class AnnotationPalette extends ObservableReactComponent<{}> {
childFiltersByRanges={returnEmptyFilter}
searchFilterDocs={returnEmptyDoclist}
/>
- )}
+ </div>
+ <DocumentView
+ Document={this._drawingCarousel}
+ addDocument={undefined}
+ addDocTab={DocumentViewInternal.addDocTabFunc}
+ pinToPres={DocumentView.PinDoc}
+ containerViewPath={returnEmptyDoclist}
+ styleProvider={DefaultStyleProvider}
+ removeDocument={returnFalse}
+ ScreenToLocalTransform={Transform.Identity}
+ PanelWidth={this.return170}
+ PanelHeight={this.return170}
+ renderDepth={1}
+ isContentActive={returnTrue}
+ focus={emptyFunction}
+ whenChildContentsActiveChanged={emptyFunction}
+ childFilters={returnEmptyFilter}
+ childFiltersByRanges={returnEmptyFilter}
+ searchFilterDocs={returnEmptyDoclist}
+ />
+ <div style={{ width: '100%', display: 'flex', flexDirection: 'row', justifyContent: 'space-between' }}>
+ <Button text="Back" tooltip="Back to All Annotations" icon={<FontAwesomeIcon icon="reply" />} color={SettingsManager.userColor} onClick={() => this.resetPalette(true)} />
+ <div style={{ display: 'flex', flexDirection: 'row' }}>
+ <Button tooltip="Save" icon={<FontAwesomeIcon icon="file-arrow-down" />} color={SettingsManager.userColor} onClick={this.saveDrawing} />
+ <Button tooltip="Reset" icon={<FontAwesomeIcon icon="rotate-left" />} color={SettingsManager.userColor} onClick={() => this.resetPalette(false)} />
+ </div>
+ </div>
</>
)}
</div>
);
}
}
+
+Docs.Prototypes.TemplateMap.set(DocumentType.ANNOPALETTE, {
+ layout: { view: AnnotationPalette, dataField: 'data' },
+ options: { acl: '' },
+});
diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx
index 24046bb83..489f6f92b 100644
--- a/src/client/views/smartdraw/SmartDrawHandler.tsx
+++ b/src/client/views/smartdraw/SmartDrawHandler.tsx
@@ -17,6 +17,7 @@ import { DocData } from '../../../fields/DocSymbols';
import { DocumentView } from '../nodes/DocumentView';
import { BoolCast, NumCast, StrCast } from '../../../fields/Types';
import './SmartDrawHandler.scss';
+import { unimplementedFunction } from '../../../Utils';
export interface DrawingOptions {
text: string;
@@ -39,15 +40,15 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
@observable private _userInput: string = '';
@observable private _showOptions: boolean = false;
@observable private _showEditBox: boolean = false;
- @observable private _showRegenerate: boolean = false;
+ @observable public _showRegenerate: boolean = false;
@observable private _complexity: number = 5;
@observable private _size: number = 200;
@observable private _autoColor: boolean = true;
@observable private _regenInput: string = '';
@observable private _canInteract: boolean = true;
- private _addFunc: (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void = () => {};
- private _deleteFunc: (doc?: Doc) => void = () => {};
- private _lastInput: DrawingOptions = { text: '', complexity: 5, size: 300, autoColor: true, x: 0, y: 0 };
+ public _addFunc: (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void = () => {};
+ public _deleteFunc: (doc?: Doc) => void = () => {};
+ private _lastInput: DrawingOptions = { text: '', complexity: 5, size: 350, autoColor: true, x: 0, y: 0 };
private _lastResponse: string = '';
private _selectedDoc: Doc | undefined = undefined;
@@ -119,51 +120,62 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
this._showOptions = false;
this._userInput = '';
this._complexity = 5;
- this._size = 300;
+ this._size = 350;
this._autoColor = true;
Doc.ActiveTool = InkTool.None;
+ this._lastInput = { text: '', complexity: 5, size: 350, autoColor: true, x: 0, y: 0 };
};
@action
hideRegenerate = () => {
- this._showRegenerate = false;
- this._isLoading = false;
- this._regenInput = '';
+ if (!this._isLoading) {
+ this._showRegenerate = false;
+ this._isLoading = false;
+ this._regenInput = '';
+ this._lastInput = { text: '', complexity: 5, size: 350, autoColor: true, x: 0, y: 0 };
+ }
};
@action
handleKeyPress = async (event: React.KeyboardEvent) => {
if (event.key === 'Enter') {
- if (this._showRegenerate) {
- this.regenerate();
- } else {
- await this.drawWithGPT({ X: this._pageX, Y: this._pageY }, this._userInput);
- this._userInput = '';
- }
+ await this.handleSendClick();
}
};
- _errorOccurredOnce = false;
@action
- drawWithGPT = async (startPt: { X: number; Y: number }, input: string) => {
- if (input === '') return;
- this._lastInput = { text: input, complexity: this._complexity, size: this._size, autoColor: this._autoColor, x: startPt.X, y: startPt.Y };
+ handleSendClick = async () => {
this._isLoading = true;
this._canInteract = false;
- this._showOptions = false;
+ if (this._showRegenerate) {
+ await this.regenerate();
+ this._regenInput = '';
+ this._showEditBox = false;
+ } else {
+ this._showOptions = false;
+ await this.drawWithGPT({ X: this._pageX, Y: this._pageY }, this._userInput, this._complexity, this._size, this._autoColor);
+ this.hideSmartDrawHandler();
+ this._showRegenerate = true;
+ }
+ this._isLoading = false;
+ this._canInteract = true;
+ };
+
+ _errorOccurredOnce = false;
+ @action
+ drawWithGPT = async (startPt: { X: number; Y: number }, input: string, complexity: number, size: number, autoColor: boolean) => {
+ if (input === '') return;
+ this._lastInput = { text: input, complexity: complexity, size: size, autoColor: autoColor, x: startPt.X, y: startPt.Y };
+
try {
- const res = await gptAPICall(`"${input}", "${this._complexity}", "${this._size}"`, GPTCallType.DRAW, undefined, true);
+ const res = await gptAPICall(`"${input}", "${complexity}", "${size}"`, GPTCallType.DRAW, undefined, true);
if (!res) {
console.error('GPT call failed');
return;
}
console.log(res);
- const strokeData = await this.parseResponse(res, startPt, false);
- this.hideSmartDrawHandler();
- this._showRegenerate = true;
+ const strokeData = await this.parseResponse(res, startPt, false, autoColor);
this._errorOccurredOnce = false;
- this._isLoading = false;
- this._canInteract = true;
return strokeData;
} catch (err) {
if (this._errorOccurredOnce) {
@@ -171,7 +183,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
this._errorOccurredOnce = false;
} else {
this._errorOccurredOnce = true;
- this.drawWithGPT(startPt, input);
+ this.drawWithGPT(startPt, input, complexity, size, autoColor);
}
}
};
@@ -182,9 +194,11 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
};
@action
- regenerate = async () => {
- this._isLoading = true;
- this._canInteract = false;
+ regenerate = async (lastInput?: DrawingOptions, lastResponse?: string, regenInput?: string) => {
+ if (lastInput) this._lastInput = lastInput;
+ if (lastResponse) this._lastResponse = lastResponse;
+ if (regenInput) this._regenInput = regenInput;
+
try {
let res;
if (this._regenInput !== '') {
@@ -199,21 +213,15 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
return;
}
console.log(res);
- this.parseResponse(res, { X: this._lastInput.x, Y: this._lastInput.y }, true);
+ this.parseResponse(res, { X: this._lastInput.x, Y: this._lastInput.y }, true, lastInput?.autoColor || this._autoColor);
} catch (err) {
console.error('GPT call failed', err);
}
- this._isLoading = false;
- this._canInteract = true;
- this._regenInput = '';
- this._showEditBox = false;
};
@action
- parseResponse = async (res: string, startPoint: { X: number; Y: number }, regenerate: boolean) => {
+ parseResponse = async (res: string, startPoint: { X: number; Y: number }, regenerate: boolean, autoColor: boolean) => {
const svg = res.match(/<svg[^>]*>([\s\S]*?)<\/svg>/g);
- console.log(svg);
- console.log('start point is', startPoint);
if (svg) {
this._lastResponse = svg[0];
const svgObject = await parse(svg[0]);
@@ -225,12 +233,12 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
convertedBezier.map(point => {
return { X: point.X + startPoint.X - this._size / 1.5, Y: point.Y + startPoint.Y - this._size / 2 };
}),
- (regenerate ? this._lastInput.autoColor : this._autoColor) ? child.attributes.stroke : undefined,
- (regenerate ? this._lastInput.autoColor : this._autoColor) ? child.attributes.fill : undefined,
+ (regenerate ? this._lastInput.autoColor : autoColor) ? child.attributes.stroke : undefined,
+ (regenerate ? this._lastInput.autoColor : autoColor) ? child.attributes.fill : undefined,
]);
});
if (regenerate) {
- this._deleteFunc(this._selectedDoc);
+ if (this._deleteFunc !== unimplementedFunction) this._deleteFunc(this._selectedDoc);
this._addFunc(strokeData, this._lastInput, svg[0], this._selectedDoc);
} else {
this._addFunc(strokeData, this._lastInput, svg[0]);
@@ -283,9 +291,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
icon={this._isLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <AiOutlineSend />}
iconPlacement="right"
color={SettingsManager.userColor}
- onClick={e => {
- this.drawWithGPT({ X: e.clientX, Y: e.clientY }, this._userInput);
- }}
+ onClick={this.handleSendClick}
/>
</div>
{this._showOptions && (
@@ -303,6 +309,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
},
}}
defaultChecked={true}
+ value={this._autoColor}
size="small"
onChange={this.setAutoColor}
/>
@@ -390,7 +397,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
tooltip="Regenerate"
icon={this._isLoading && this._regenInput === '' ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <FontAwesomeIcon icon={'rotate'} />}
color={SettingsManager.userColor}
- onClick={this.regenerate}
+ onClick={this.handleSendClick}
/>
<IconButton tooltip="Edit with GPT" icon={<FontAwesomeIcon icon="pen-to-square" />} color={SettingsManager.userColor} onClick={this.edit} />
{this._showEditBox && (
@@ -418,7 +425,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
icon={this._isLoading && this._regenInput !== '' ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <AiOutlineSend />}
iconPlacement="right"
color={SettingsManager.userColor}
- onClick={this.regenerate}
+ onClick={this.handleSendClick}
/>
</div>
)}