From 5d0dd1de740a8e1fa589ebf7dc7a9f7df0db63b9 Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Mon, 8 Jul 2024 12:52:54 -0400 Subject: switched to iink-ts not functional --- src/client/views/MainView.tsx | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/client/views/MainView.tsx') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 31d88fb87..0dcf2fa79 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -76,6 +76,7 @@ import { PresBox } from './nodes/trails'; import { AnchorMenu } from './pdf/AnchorMenu'; import { GPTPopup } from './pdf/GPTPopup/GPTPopup'; import { TopBar } from './topbar/TopBar'; +import { InkTranscription } from './InkTranscription'; const { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } = require('./global/globalCssVariables.module.scss'); // prettier-ignore const _global = (window /* browser */ || global) /* node */ as any; @@ -1096,6 +1097,7 @@ export class MainView extends ObservableReactComponent<{}> { + {this.snapLines} -- cgit v1.2.3-70-g09d2 From 49b3c7cbe01f830a2b1d2c02452901fe360348d3 Mon Sep 17 00:00:00 2001 From: eleanor-park Date: Thu, 11 Jul 2024 11:50:01 -0400 Subject: updates --- src/client/util/CurrentUserUtils.ts | 28 ++ src/client/util/bezierFit.ts | 1 - src/client/views/DocumentButtonBar.tsx | 25 +- src/client/views/GlobalKeyHandler.ts | 2 +- src/client/views/LightboxView.tsx | 7 +- src/client/views/MainView.tsx | 10 + .../collectionFreeForm/CollectionFreeFormView.tsx | 18 +- .../collectionFreeForm/MarqueeOptionsMenu.tsx | 3 +- src/client/views/smartdraw/AnnotationPalette.scss | 10 + src/client/views/smartdraw/AnnotationPalette.tsx | 337 +++++++++++++++++++++ src/client/views/smartdraw/DrawingPalette.scss | 11 - src/client/views/smartdraw/DrawingPalette.tsx | 89 ------ src/client/views/smartdraw/SmartDrawHandler.scss | 3 + src/client/views/smartdraw/SmartDrawHandler.tsx | 95 +++--- src/fields/Doc.ts | 6 +- 15 files changed, 493 insertions(+), 152 deletions(-) create mode 100644 src/client/views/smartdraw/AnnotationPalette.scss create mode 100644 src/client/views/smartdraw/AnnotationPalette.tsx delete mode 100644 src/client/views/smartdraw/DrawingPalette.scss delete mode 100644 src/client/views/smartdraw/DrawingPalette.tsx create mode 100644 src/client/views/smartdraw/SmartDrawHandler.scss (limited to 'src/client/views/MainView.tsx') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 141695d86..24a5de42b 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -162,6 +162,33 @@ export class CurrentUserUtils { const reqdScripts = { dropConverter: "convertToButtons(dragData)" }; return DocUtils.AssignDocField(doc, field, (opts,items) => Docs.Create.TreeDocument(items??[], opts), reqdOpts, templates, reqdScripts); } + + static setupAnnoPalette(doc: Doc, field="myAnnos") { + const reqdOpts:DocumentOptions = { + title: "Saved Annotations", _xMargin: 0, _layout_showTitle: "title", _chromeHidden: true, hidden: false, + _dragOnlyWithinContainer: true, layout_hideContextMenu: true, isSystem: true, _forceActive: true, + _layout_autoHeight: true, _width: 500, _height: 300, _layout_fitWidth: true, _columnWidth: 35, ignoreClick: true, _lockedPosition: true, + }; + const reqdScripts = { dropConverter: "convertToButtons(dragData)" }; + const savedAnnos = DocCast(doc[field]); + return DocUtils.AssignDocField(doc, field, (opts,items) => Docs.Create.MasonryDocument(items??[], opts), reqdOpts, DocListCast(savedAnnos?.data), reqdScripts); + } + + // static setupNoteTemplates(doc: Doc, field="template_notes") { + // const tempNotes = DocCast(doc[field]); + // const reqdTempOpts:DocumentOptions[] = [ + // { title: "Postit", backgroundColor: "yellow", icon: "sticky-note", _layout_showTitle: "title", layout_borderRounding: "5px"}, + // { title: "Idea", backgroundColor: "pink", icon: "lightbulb" , _layout_showTitle: "title"}, + // { title: "Topic", backgroundColor: "lightblue", icon: "book-open" , _layout_showTitle: "title"}]; + // const reqdNoteList = [...reqdTempOpts.map(opts => { + // const reqdOpts = {...opts, isSystem:true, width:200, layout_autoHeight: true, layout_fitWidth: true}; + // const noteTemp = tempNotes ? DocListCast(tempNotes.data).find(fdoc => fdoc.title === opts.title): undefined; + // return DocUtils.AssignOpts(noteTemp, reqdOpts) ?? MakeTemplate(Docs.Create.TextDocument("",reqdOpts)); + // }), ... DocListCast(tempNotes?.data).filter(note => !reqdTempOpts.find(reqd => reqd.title === note.title))]; + + // const reqdOpts:DocumentOptions = { title: "Note Layouts", _height: 75, isSystem: true }; + // // eslint-disable-next-line no-return-assign + // r // setup templates for different document types when they are iconified from Document Decorations static setupDefaultIconTemplates(doc: Doc, field="template_icons") { @@ -986,6 +1013,7 @@ pie title Minerals in my tap water this.setupTopbarButtons(doc); this.setupDockedButtons(doc); // the bottom bar of font icons this.setupLeftSidebarMenu(doc); // the left-side column of buttons that open their contents in a flyout panel on the left + this.setupAnnoPalette(doc); this.setupDocTemplates(doc); // sets up the template menu of templates // sthis.setupFieldInfos(doc); // sets up the collection of field info descriptions for each possible DocumentOption DocUtils.AssignDocField(doc, "globalScriptDatabase", () => Docs.Prototypes.MainScriptDocument(), {}); diff --git a/src/client/util/bezierFit.ts b/src/client/util/bezierFit.ts index f5696afaf..98a6feea0 100644 --- a/src/client/util/bezierFit.ts +++ b/src/client/util/bezierFit.ts @@ -627,7 +627,6 @@ export function GenerateControlPoints(coordinates: Point[], alpha = 0.1) { } export function SVGToBezier(name: SVGType, attributes: any): Point[] { - console.log('in svg to bezier', name, attributes); switch (name) { case 'line': const x1 = parseInt(attributes.x1); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 487868169..177546fdc 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -12,7 +12,7 @@ import * as React from 'react'; import { FaEdit } from 'react-icons/fa'; import { returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick } from '../../ClientUtils'; import { emptyFunction } from '../../Utils'; -import { Doc } from '../../fields/Doc'; +import { Doc, DocListCast } from '../../fields/Doc'; import { Cast, DocCast } from '../../fields/Types'; import { DocUtils, IsFollowLinkScript } from '../documents/DocUtils'; import { CalendarManager } from '../util/CalendarManager'; @@ -31,6 +31,8 @@ import { DocumentLinksButton } from './nodes/DocumentLinksButton'; import { DocumentView } from './nodes/DocumentView'; import { OpenWhere } from './nodes/OpenWhere'; import { DashFieldView } from './nodes/formattedText/DashFieldView'; +import { AnnotationPalette } from './smartdraw/AnnotationPalette'; +import { DocData } from '../../fields/DocSymbols'; @observer export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (DocumentView | undefined)[]; stack?: any }> { @@ -241,6 +243,26 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => ( ); } + @observable _annoSaved: boolean = false; + @action + saveAnno = (targetDoc: Doc) => { + targetDoc.savedAsAnno = true; + this._annoSaved = true; + AnnotationPalette.Instance.saveAnno(this.view0, targetDoc); + }; + @computed + get saveAnnoButton() { + const targetDoc = this.view0?.Document; + if (targetDoc && targetDoc.savedAsAnno) this._annoSaved = true; + return !targetDoc ? null : ( + {this._annoSaved ? 'Saved as Annotation!' : 'Save to Annotation Palette'}}> +
this.saveAnno(targetDoc)}> + +
+
+ ); + } + @computed get shareButton() { const targetDoc = this.view0?.Document; @@ -450,6 +472,7 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => (
{this.templateButton}
{!DocumentView.Selected().some(v => v.allLinks.length) ? null :
{this.followLinkButton}
}
{this.pinButton}
+
{this.saveAnnoButton}
{this.recordButton}
{this.calendarButton}
{!Doc.UserDoc().documentLinksButton_fullMenu ? null :
{this.shareButton}
} diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index 7d01bbabb..562827db5 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -162,7 +162,7 @@ export class KeyManager { case 'delete': case 'backspace': if (document.activeElement?.tagName !== 'INPUT' && document.activeElement?.tagName !== 'TEXTAREA') { - if (DocumentView.LightboxDoc()) { + if (DocumentView.LightboxDoc() && !DocumentView.Selected().length) { DocumentView.SetLightboxDoc(undefined); DocumentView.DeselectAll(); } else if (!window.getSelection()?.toString()) DocumentDecorations.Instance.onCloseClick(true); diff --git a/src/client/views/LightboxView.tsx b/src/client/views/LightboxView.tsx index e93e4949b..dcd5a61c7 100644 --- a/src/client/views/LightboxView.tsx +++ b/src/client/views/LightboxView.tsx @@ -23,7 +23,7 @@ import { DocumentView } from './nodes/DocumentView'; import { OpenWhere, OpenWhereMod } from './nodes/OpenWhere'; import { ScriptingGlobals } from '../util/ScriptingGlobals'; import { OverlayView } from './OverlayView'; -import { DrawingPalette } from './smartdraw/DrawingPalette'; +import { AnnotationPalette } from './smartdraw/AnnotationPalette'; interface LightboxViewProps { PanelWidth: number; @@ -73,6 +73,7 @@ export class LightboxView extends ObservableReactComponent { DocumentView._lightboxContains = LightboxView.Contains; DocumentView._lightboxDoc = LightboxView.LightboxDoc; } + /** * Sets the root Doc to render in the lightbox view. * @param doc @@ -105,6 +106,8 @@ export class LightboxView extends ObservableReactComponent { this._history = []; Doc.ActiveTool = InkTool.None; SnappingManager.SetExploreMode(false); + AnnotationPalette.Instance.displayPalette(false); + this._showPalette = false; } DocumentView.DeselectAll(); if (future) { @@ -206,6 +209,7 @@ export class LightboxView extends ObservableReactComponent { }; togglePalette = () => { this._showPalette = !this._showPalette; + AnnotationPalette.Instance.displayPalette(this._showPalette); }; togglePen = () => { Doc.ActiveTool = Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen; @@ -327,7 +331,6 @@ export class LightboxView extends ObservableReactComponent { {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)} - {this._showPalette && } ); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index dd11ac684..54bbf21e5 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -77,6 +77,7 @@ import { AnchorMenu } from './pdf/AnchorMenu'; import { GPTPopup } from './pdf/GPTPopup/GPTPopup'; import { TopBar } from './topbar/TopBar'; import { SmartDrawHandler } from './smartdraw/SmartDrawHandler'; +import { AnnotationPalette } from './smartdraw/AnnotationPalette'; const { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } = require('./global/globalCssVariables.module.scss'); // prettier-ignore const _global = (window /* browser */ || global) /* node */ as any; @@ -380,6 +381,7 @@ export class MainView extends ObservableReactComponent<{}> { fa.faXmark, fa.faExclamation, fa.faFileAlt, + fa.faFileArrowDown, fa.faFileAudio, fa.faFileVideo, fa.faFilePdf, @@ -434,6 +436,7 @@ export class MainView extends ObservableReactComponent<{}> { fa.faBold, fa.faItalic, fa.faClipboard, + fa.faClipboardCheck, fa.faUnderline, fa.faStrikethrough, fa.faSuperscript, @@ -481,6 +484,7 @@ export class MainView extends ObservableReactComponent<{}> { fa.faHashtag, fa.faAlignJustify, fa.faCheckSquare, + fa.faSquarePlus, fa.faListUl, fa.faWindowMinimize, fa.faWindowRestore, @@ -576,6 +580,9 @@ export class MainView extends ObservableReactComponent<{}> { Doc.linkFollowUnhighlight(); AudioBox.Enabled = true; const targets = document.elementsFromPoint(e.x, e.y); + const targetClasses: string[] = targets.map(target => { + return target.className.toString(); + }); if (targets.length) { let targClass = targets[0].className.toString(); for (let i = 0; i < targets.length - 1; i++) { @@ -583,6 +590,8 @@ export class MainView extends ObservableReactComponent<{}> { else break; } !targClass.includes('contextMenu') && ContextMenu.Instance.closeMenu(); + !targetClasses.includes('marqueeView') && !targetClasses.includes('smart-draw-handler') && SmartDrawHandler.Instance.hideSmartDrawHandler(); + !targetClasses.includes('smart-draw-handler') && SmartDrawHandler.Instance.hideRegenerate(); !['timeline-menu-desc', 'timeline-menu-item', 'timeline-menu-input'].includes(targClass) && TimelineMenu.Instance.closeMenu(); } }); @@ -1106,6 +1115,7 @@ export class MainView extends ObservableReactComponent<{}> { + ); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 0bdcc8450..779d16a9c 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1269,8 +1269,11 @@ export class CollectionFreeFormView extends CollectionSubView, strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => { + createDrawing = (strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => { + this._drawing = []; + 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); @@ -1294,12 +1297,13 @@ export class CollectionFreeFormView extends CollectionSubView { this._batch = UndoManager.StartBatch('regenerateDrawing'); if (doc) { - const docData: Doc = doc[DocData]; - const children = docData.data as unknown as Doc[]; - this._props.removeDocument?.(doc); + const docData = DocCast(doc[DocData]); + const children = DocListCast(docData.data); this._props.removeDocument?.(children); + this._props.removeDocument?.(doc); } else { this._props.removeDocument?.(this._drawing); + if (this._drawingContainer) this._props.removeDocument?.(this._drawingContainer); } - this._drawing = []; }; @action @@ -2021,7 +2025,7 @@ export class CollectionFreeFormView extends CollectionSubView { this._showDrawingEditor = !this._showDrawingEditor; this._showDrawingEditor ? SmartDrawHandler.Instance.displayRegenerate(this._downX, this._downY - 10, this.createDrawing, this.removeDrawing) : SmartDrawHandler.Instance.hideRegenerate(); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx index f02cd9d45..b3fdd9379 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeOptionsMenu.tsx @@ -3,6 +3,7 @@ import { IconButton } from 'browndash-components'; import { computed, makeObservable } from 'mobx'; import { observer } from 'mobx-react'; import * as React from 'react'; +import { Doc } from '../../../../fields/Doc'; import { unimplementedFunction } from '../../../../Utils'; import { SettingsManager } from '../../../util/SettingsManager'; import { AntimodeMenu, AntimodeMenuProps } from '../../AntimodeMenu'; @@ -12,7 +13,7 @@ export class MarqueeOptionsMenu extends AntimodeMenu { // eslint-disable-next-line no-use-before-define static Instance: MarqueeOptionsMenu; - public createCollection: (e: KeyboardEvent | React.PointerEvent | undefined, group?: boolean) => void = unimplementedFunction; + public createCollection: (e: KeyboardEvent | React.PointerEvent | undefined, group?: boolean, selection?: Doc[]) => Doc | void = unimplementedFunction; public delete: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction; public summarize: (e: KeyboardEvent | React.PointerEvent | undefined) => void = unimplementedFunction; public showMarquee: () => void = unimplementedFunction; diff --git a/src/client/views/smartdraw/AnnotationPalette.scss b/src/client/views/smartdraw/AnnotationPalette.scss new file mode 100644 index 000000000..9f875f61a --- /dev/null +++ b/src/client/views/smartdraw/AnnotationPalette.scss @@ -0,0 +1,10 @@ +.annotation-palette { + display: flex; + flex-direction: column; + align-items: center; + position: absolute; + right: 14px; + top: 50px; + border-radius: 5px; + margin: auto; +} diff --git a/src/client/views/smartdraw/AnnotationPalette.tsx b/src/client/views/smartdraw/AnnotationPalette.tsx new file mode 100644 index 000000000..10e88e91e --- /dev/null +++ b/src/client/views/smartdraw/AnnotationPalette.tsx @@ -0,0 +1,337 @@ +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 { DocData } from '../../../fields/DocSymbols'; +import { InkData, InkField } from '../../../fields/InkField'; +import { BoolCast, DocCast } from '../../../fields/Types'; +import { emptyFunction } from '../../../Utils'; +import { Docs } from '../../documents/Documents'; +import { CollectionViewType } from '../../documents/DocumentTypes'; +import { DragManager } from '../../util/DragManager'; +import { convertDropDataToButtons, 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 { ObservableReactComponent } from '../ObservableReactComponent'; +import { DefaultStyleProvider } from '../StyleProvider'; +import './AnnotationPalette.scss'; +import { SmartDrawHandler } from './SmartDrawHandler'; + +@observer +export class AnnotationPalette extends ObservableReactComponent<{}> { + static Instance: AnnotationPalette; + @observable private _savedDrawings: Doc[] = []; + // @observable private _marqueeViewRef = React.createRef(); + @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; + + constructor(props: any) { + super(props); + makeObservable(this); + AnnotationPalette.Instance = this; + } + + return170 = () => 170; + + @action + setPaletteMode = (mode: 'create' | 'view') => { + this._paletteMode = mode; + }; + + @action + setUserInput = (input: string) => { + this._userInput = input; + }; + + @action + setDetail = (detail: number) => { + this._detail = detail; + }; + + @action + setSize = (size: number) => { + this._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); + + // 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); + }; + + @action + displayPalette = (display: boolean) => { + this._display = display; + }; + + @action + generateDrawing = 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._showDrawing = true; + } catch (e) { + console.log('Error generating drawing'); + } + this._isLoading = false; + }; + + // @computed get drawingCreator() { + // return ( + // MarqueeOptionsMenu.Instance.createCollection(undefined, true, this._drawing); + // ); + // } + // return Docs.Create.FreeformDocument([], {}); + // Docs.Create. + // return ( + // + // ); + + render() { + return !this._display ? null : ( +
+ {this._paletteMode === 'view' && ( + <> + +
+
+
+ Color + +
+
+ Detail + { + this.setDetail(val as number); + }} + valueLabelDisplay="auto" + /> +
+
+ Size + { + this.setSize(val as number); + }} + valueLabelDisplay="auto" + /> +
+
+ {this._drawing !== undefined && ( + + )} + + )} + + ); + } +} diff --git a/src/client/views/smartdraw/DrawingPalette.scss b/src/client/views/smartdraw/DrawingPalette.scss deleted file mode 100644 index 0f1152b71..000000000 --- a/src/client/views/smartdraw/DrawingPalette.scss +++ /dev/null @@ -1,11 +0,0 @@ -.drawing-palette { - display: grid; - grid-template-columns: auto; - position: absolute; - right: 14px; - width: 170px; - height: 170px; - top: 50px; - border-radius: 5px; - background-color: white; -} diff --git a/src/client/views/smartdraw/DrawingPalette.tsx b/src/client/views/smartdraw/DrawingPalette.tsx deleted file mode 100644 index 87a39bc85..000000000 --- a/src/client/views/smartdraw/DrawingPalette.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { computed, makeObservable, observable } from 'mobx'; -import { observer } from 'mobx-react'; -import * as React from 'react'; -import { returnAll, returnFalse, returnOne, returnZero } from '../../../ClientUtils'; -import { Doc, StrListCast } from '../../../fields/Doc'; -import { emptyFunction } from '../../../Utils'; -import { CollectionViewType } from '../../documents/DocumentTypes'; -import { MarqueeView } from '../collections/collectionFreeForm'; -import { CollectionGridView } from '../collections/collectionGrid'; -import { CollectionStackingView } from '../collections/CollectionStackingView'; -import { DocumentView } from '../nodes/DocumentView'; -import { FieldViewProps } from '../nodes/FieldView'; -import { ObservableReactComponent } from '../ObservableReactComponent'; -import './DrawingPalette.scss'; - -@observer -export class DrawingPalette extends ObservableReactComponent<{}> { - @observable private _savedDrawings: Doc[] = []; - @observable _marqueeViewRef = React.createRef(); - private _stackRef = React.createRef(); - - constructor(props: any) { - super(props); - makeObservable(this); - } - - panelWidth = () => 100; - panelHeight = () => 100; - - getCollection = () => { - return this._marqueeViewRef.current?.collection(undefined, false, this._savedDrawings) || new Doc(); - }; - - @computed get savedDrawingAnnos() { - // const savedAnnos = Doc.MyDrawingAnnos; - return ( -
- {/* */} - {/* */} -
- ); - } - - render() { - return ( -
- {/* {this._savedDrawings.map(doc => { - return ; - })} */} - {/* */} - {} - {/* */} - {this.savedDrawingAnnos} -
- ); - } -} diff --git a/src/client/views/smartdraw/SmartDrawHandler.scss b/src/client/views/smartdraw/SmartDrawHandler.scss new file mode 100644 index 000000000..6d402a80f --- /dev/null +++ b/src/client/views/smartdraw/SmartDrawHandler.scss @@ -0,0 +1,3 @@ +.smart-draw-handler { + position: absolute; +} diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx index d24cc9d50..24046bb83 100644 --- a/src/client/views/smartdraw/SmartDrawHandler.tsx +++ b/src/client/views/smartdraw/SmartDrawHandler.tsx @@ -7,15 +7,16 @@ import { ObservableReactComponent } from '../ObservableReactComponent'; import { Button, IconButton } from 'browndash-components'; import ReactLoading from 'react-loading'; import { AiOutlineSend } from 'react-icons/ai'; -// import './ImageLabelHandler.scss'; import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT'; -import { InkData } from '../../../fields/InkField'; +import { InkData, InkTool } from '../../../fields/InkField'; import { SVGToBezier } from '../../util/bezierFit'; const { parse } = require('svgson'); import { Slider, Switch } from '@mui/material'; import { Doc } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { DocumentView } from '../nodes/DocumentView'; +import { BoolCast, NumCast, StrCast } from '../../../fields/Types'; +import './SmartDrawHandler.scss'; export interface DrawingOptions { text: string; @@ -43,7 +44,8 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { @observable private _size: number = 200; @observable private _autoColor: boolean = true; @observable private _regenInput: string = ''; - private _addFunc: (e: React.PointerEvent, strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void = () => {}; + @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 }; private _lastResponse: string = ''; @@ -57,12 +59,12 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { @action setUserInput = (input: string) => { - this._userInput = input; + if (this._canInteract) this._userInput = input; }; @action setRegenInput = (input: string) => { - this._regenInput = input; + if (this._canInteract) this._regenInput = input; }; @action @@ -72,21 +74,21 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { @action setComplexity = (val: number) => { - this._complexity = val; + if (this._canInteract) this._complexity = val; }; @action setSize = (val: number) => { - this._size = val; + if (this._canInteract) this._size = val; }; @action setAutoColor = () => { - this._autoColor = !this._autoColor; + if (this._canInteract) this._autoColor = !this._autoColor; }; @action - displaySmartDrawHandler = (x: number, y: number, addFunc: (e: React.PointerEvent, strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void, deleteFunc: (doc?: Doc) => void) => { + displaySmartDrawHandler = (x: number, y: number, addFunc: (strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void, deleteFunc: (doc?: Doc) => void) => { this._pageX = x; this._pageY = y; this._display = true; @@ -95,16 +97,18 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { }; @action - displayRegenerate = (x: number, y: number, addFunc: (e: React.PointerEvent, strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void, deleteFunc: (doc?: Doc) => void) => { + displayRegenerate = (x: number, y: number, addFunc: (strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void, deleteFunc: (doc?: Doc) => void) => { this._selectedDoc = DocumentView.SelectedDocs().lastElement(); const docData = this._selectedDoc[DocData]; this._addFunc = addFunc; this._deleteFunc = deleteFunc; this._pageX = x; this._pageY = y; + this._display = false; this._showRegenerate = true; - this._lastResponse = docData.drawingData as string; - this._lastInput = { text: docData.drawingInput as string, complexity: docData.drawingComplexity as number, size: docData.drawingSize as number, autoColor: docData.drawingColored as boolean, x: this._pageX, y: this._pageY }; + this._showEditBox = false; + this._lastResponse = StrCast(docData.drawingData); + this._lastInput = { text: StrCast(docData.drawingInput), complexity: NumCast(docData.drawingComplexity), size: NumCast(docData.drawingSize), autoColor: BoolCast(docData.drawingColored), x: this._pageX, y: this._pageY }; }; @action @@ -117,7 +121,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { this._complexity = 5; this._size = 300; this._autoColor = true; - // this._regenInput = '' + Doc.ActiveTool = InkTool.None; }; @action @@ -127,12 +131,25 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { this._regenInput = ''; }; + @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 = ''; + } + } + }; + _errorOccurredOnce = false; @action - drawWithGPT = async (e: React.PointerEvent, input: string) => { + 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: e.clientX, y: e.clientY }; + this._lastInput = { text: input, complexity: this._complexity, size: this._size, autoColor: this._autoColor, x: startPt.X, y: startPt.Y }; this._isLoading = true; + this._canInteract = false; this._showOptions = false; try { const res = await gptAPICall(`"${input}", "${this._complexity}", "${this._size}"`, GPTCallType.DRAW, undefined, true); @@ -141,20 +158,22 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { return; } console.log(res); - await this.parseResponse(e, res, { X: e.clientX, Y: e.clientY }, false); + const strokeData = await this.parseResponse(res, startPt, false); this.hideSmartDrawHandler(); this._showRegenerate = true; this._errorOccurredOnce = false; + this._isLoading = false; + this._canInteract = true; + return strokeData; } catch (err) { if (this._errorOccurredOnce) { console.error('GPT call failed', err); this._errorOccurredOnce = false; } else { this._errorOccurredOnce = true; - this.drawWithGPT(e, input); + this.drawWithGPT(startPt, input); } } - this._isLoading = false; }; @action @@ -163,14 +182,15 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { }; @action - regenerate = async (e: React.PointerEvent) => { + regenerate = async () => { this._isLoading = true; + this._canInteract = false; try { let res; if (this._regenInput !== '') { const prompt: string = `This is your previously generated svg code: ${this._lastResponse} for the user input "${this._lastInput.text}". Please regenerate it with the provided specifications.`; res = await gptAPICall(`"${this._regenInput}"`, GPTCallType.DRAW, prompt, true); - this._lastInput.text = `${this._lastInput.text} + ${this._regenInput}`; + this._lastInput.text = `${this._lastInput.text} ~~~ ${this._regenInput}`; } else { res = await gptAPICall(`"${this._lastInput.text}", "${this._lastInput.complexity}", "${this._lastInput.size}"`, GPTCallType.DRAW, undefined, true); } @@ -179,25 +199,26 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { return; } console.log(res); - this.parseResponse(e, res, { X: this._lastInput.x, Y: this._lastInput.y }, true); + this.parseResponse(res, { X: this._lastInput.x, Y: this._lastInput.y }, true); } catch (err) { console.error('GPT call failed', err); } this._isLoading = false; + this._canInteract = true; this._regenInput = ''; this._showEditBox = false; }; @action - parseResponse = async (e: React.PointerEvent, res: string, startPoint: { X: number; Y: number }, regenerate: boolean) => { + parseResponse = async (res: string, startPoint: { X: number; Y: number }, regenerate: boolean) => { const svg = res.match(/]*>([\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]); const svgStrokes: any = svgObject.children; const strokeData: [InkData, string, string][] = []; - console.log('autocolor is', this._autoColor); svgStrokes.forEach((child: any) => { const convertedBezier: InkData = SVGToBezier(child.name, child.attributes); strokeData.push([ @@ -210,10 +231,11 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { }); if (regenerate) { this._deleteFunc(this._selectedDoc); - this._addFunc(e, strokeData, this._lastInput, svg[0], this._selectedDoc); + this._addFunc(strokeData, this._lastInput, svg[0], this._selectedDoc); } else { - this._addFunc(e, strokeData, this._lastInput, svg[0]); + this._addFunc(strokeData, this._lastInput, svg[0]); } + return { data: strokeData, lastInput: this._lastInput, lastRes: svg[0] }; } }; @@ -222,7 +244,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { return (
{ style={{ width: '19px' }} /> { this.setUserInput(e.target.value); }} placeholder="Enter item to draw" + onKeyDown={this.handleKeyPress} /> + } color={SettingsManager.userColor} style={{ width: '14px' }} onClick={this.setShowOptions} />
@@ -349,7 +374,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { return (
{ tooltip="Regenerate" icon={this._isLoading && this._regenInput === '' ? : } color={SettingsManager.userColor} - onClick={e => { - this.regenerate(e as React.PointerEvent); - }} + onClick={this.regenerate} /> } color={SettingsManager.userColor} onClick={this.edit} /> {this._showEditBox && ( @@ -378,6 +401,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { }}> { onChange={e => { this.setRegenInput(e.target.value); }} + onKeyDown={this.handleKeyPress} placeholder="Edit instructions" />
)} diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index bc1abd26e..c86342870 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -276,7 +276,7 @@ export class Doc extends RefField { public static get MyPublishedDocs() { return DocListCast(Doc.ActiveDashboard?.myPublishedDocs).concat(DocListCast(DocCast(Doc.UserDoc().myPublishedDocs)?.data)); } // prettier-ignore public static get MyDashboards() { return DocCast(Doc.UserDoc().myDashboards); } // prettier-ignore public static get MyTemplates() { return DocCast(Doc.UserDoc().myTemplates); } // prettier-ignore - public static get MyDrawingAnnos() { return DocCast(Doc.UserDoc().myDrawingAnnos); } // prettier-ignore + public static get MyAnnos() { return DocCast(Doc.UserDoc().myAnnos); } // prettier-ignore public static get MyImports() { return DocCast(Doc.UserDoc().myImports); } // prettier-ignore public static get MyFilesystem() { return DocCast(Doc.UserDoc().myFilesystem); } // prettier-ignore public static get MyTools() { return DocCast(Doc.UserDoc().myTools); } // prettier-ignore @@ -1741,8 +1741,8 @@ ScriptingGlobals.add(function getEmbedding(doc: any) { return Doc.MakeEmbedding(doc); }); // eslint-disable-next-line prefer-arrow-callback -ScriptingGlobals.add(function getCopy(doc: any, copyProto: any) { - return doc.isTemplateDoc ? Doc.MakeDelegateWithProto(doc) : Doc.MakeCopy(doc, copyProto); +ScriptingGlobals.add(async function getCopy(doc: any, copyProto: any) { + return doc.isTemplateDoc ? (doc.isGroup ? (await Doc.MakeClone(doc)).clone : Doc.MakeDelegateWithProto(doc)) : Doc.MakeCopy(doc, copyProto); }); // eslint-disable-next-line prefer-arrow-callback ScriptingGlobals.add(function copyField(field: any) { -- cgit v1.2.3-70-g09d2 From a0e9c3471c1a8adcb7cc68b430735e023fe35654 Mon Sep 17 00:00:00 2001 From: Zachary Zhang Date: Thu, 18 Jul 2024 14:21:54 -0400 Subject: gesture improvements --- src/client/views/GestureOverlay.tsx | 8 +++ src/client/views/InkTranscription.tsx | 19 +++++-- src/client/views/MainView.tsx | 2 +- src/pen-gestures/GestureTypes.ts | 1 + src/pen-gestures/ndollar.ts | 96 +++++++++++++++++++++++++++++++++++ 5 files changed, 121 insertions(+), 5 deletions(-) (limited to 'src/client/views/MainView.tsx') diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index e3e252593..e961bc031 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -94,6 +94,7 @@ export class GestureOverlay extends ObservableReactComponent { + console.log('pointerdown'); if (!(e.target as any)?.className?.toString().startsWith('lm_')) { if ([InkTool.Highlighter, InkTool.Pen, InkTool.Write].includes(Doc.ActiveTool)) { this._points.push({ X: e.clientX, Y: e.clientY }); @@ -132,6 +133,7 @@ export class GestureOverlay extends ObservableReactComponent { + console.log('pointer up'); DocumentView.DownDocView = undefined; if (this._points.length > 1) { const B = this.svgBounds; @@ -147,7 +149,9 @@ export class GestureOverlay extends ObservableReactComponent 2 && GestureUtils.GestureRecognizer.Recognize([points]); + console.log(points); let actionPerformed = false; + console.log(result); if (Doc.UserDoc().recognizeGestures && result && result.Score > 0.7) { switch (result.Name) { case Gestures.Line: @@ -156,10 +160,14 @@ export class GestureOverlay extends ObservableReactComponent inkStroke.ptToScreen({ X: pd.X, Y: pd.Y }))); times.push(DateCast(i.author_date).getDate().getTime()); }); - + console.log(strokes); + console.log(this.convertPointsToString(strokes)); + console.log(this.convertPointsToString2(strokes)); this.currGroup = groupDoc; const pointerData = strokes.map((stroke, i) => this.inkJSON(stroke, times[i])); - console.log(JSON.stringify(pointerData)); const processGestures = false; if (math) { console.log('math'); @@ -135,6 +136,12 @@ export class InkTranscription extends React.Component { this.iinkEditor.importPointEvents(pointerData); } }; + convertPointsToString(points: InkData[]): string { + return points[0].map(point => `new Point(${point.X}, ${point.Y})`).join(',\n '); + } + convertPointsToString2(points: InkData[]): string { + return points[0].map(point => `(${point.X},${point.Y})`).join(','); + } /** * Converts the Dash Ink Data to JSON. @@ -253,6 +260,8 @@ export class InkTranscription extends React.Component { this.currGroup.title = text; let image = await this.getIcon(); const pathname = image?.url.href as string; + console.log(image?.url); + console.log(image); const { href } = (image as URLField).url; const hrefParts = href.split('.'); const hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`; @@ -267,7 +276,7 @@ export class InkTranscription extends React.Component { const textBoxText = 'iink: ' + text + '\n' + '\n' + 'ChatGPT: ' + response; if (!this.currGroup.hasTextBox) { const newDoc = Docs.Create.TextDocument(textBoxText, { title: '', x: this.currGroup.x as number, y: (this.currGroup.y as number) + (this.currGroup.height as number) }); - newDoc.width = 100; + newDoc.height = 200; this.collectionFreeForm?.addDocument(newDoc); this.currGroup.hasTextBox = true; } @@ -278,9 +287,11 @@ export class InkTranscription extends React.Component { }; async getIcon() { const docView = DocumentView.getDocumentView(this.currGroup); + console.log(this.currGroup); if (docView) { + console.log(docView); docView.ComponentView?.updateIcon?.(); - return new Promise(res => setTimeout(() => res(ImageCast(docView.Document.icon)), 500)); + return new Promise(res => setTimeout(() => res(ImageCast(docView.Document.icon)), 1000)); } return undefined; } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 8a3b0f27c..f8c7fd7b1 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -1097,7 +1097,7 @@ export class MainView extends ObservableReactComponent<{}> { - + {this.snapLines} diff --git a/src/pen-gestures/GestureTypes.ts b/src/pen-gestures/GestureTypes.ts index d86562580..2e1c9d16f 100644 --- a/src/pen-gestures/GestureTypes.ts +++ b/src/pen-gestures/GestureTypes.ts @@ -7,6 +7,7 @@ export enum Gestures { Circle = 'circle', Rectangle = 'rectangle', Arrow = 'arrow', + RightAngle = 'rightangle', } // Defines a point in an ink as a pair of x- and y-coordinates. diff --git a/src/pen-gestures/ndollar.ts b/src/pen-gestures/ndollar.ts index ff7f7310b..31a4eb0e8 100644 --- a/src/pen-gestures/ndollar.ts +++ b/src/pen-gestures/ndollar.ts @@ -209,6 +209,7 @@ export class NDollarRecognizer { ]) ) ); + this.Multistrokes.push(new Multistroke(Gestures.Rectangle, useBoundedRotationInvariance, new Array([new Point(30, 143), new Point(106, 146), new Point(106, 225), new Point(30, 222), new Point(30, 146)]))); this.Multistrokes.push(new Multistroke(Gestures.Line, useBoundedRotationInvariance, [[new Point(12, 347), new Point(119, 347)]])); this.Multistrokes.push( new Multistroke( @@ -217,6 +218,13 @@ export class NDollarRecognizer { new Array([new Point(40, 100), new Point(100, 200), new Point(140, 102), new Point(42, 100)]) ) ); + this.Multistrokes.push( + new Multistroke( + Gestures.Triangle, // equilateral + useBoundedRotationInvariance, + new Array([new Point(42, 100), new Point(140, 102), new Point(100, 200), new Point(40, 100)]) + ) + ); this.Multistrokes.push( new Multistroke( Gestures.Circle, @@ -236,6 +244,94 @@ export class NDollarRecognizer { ]) ) ); + this.Multistrokes.push( + new Multistroke( + Gestures.Circle, + useBoundedRotationInvariance, + new Array([ + new Point(201, 250), + new Point(160, 230), + new Point(151, 210), + new Point(151, 190), + new Point(160, 170), + new Point(200, 150), + new Point(240, 170), + new Point(248, 190), + new Point(248, 210), + new Point(240, 230), + new Point(200, 250), + ]) + ) + ); + this.Multistrokes.push( + new Multistroke( + Gestures.Scribble, + useBoundedRotationInvariance, + new Array([ + new Point(232.43359374999994, 428.3789062499997), + new Point(232.43359374999994, 382.0359155790783), + new Point(265.26320387389393, 340.59025405258205), + new Point(285.92968749999994, 300.6953124999997), + new Point(285.92968749999994, 300.6953124999997), + new Point(290.29904726504463, 292.260623967478), + new Point(294.85514947688137, 276.5586112000384), + new Point(301.80468749999994, 270.1054687499997), + new Point(301.80468749999994, 270.1054687499997), + new Point(303.30831790356257, 268.7092405181201), + new Point(302.3387333271824, 274.174445118092), + new Point(302.58984374999994, 276.2109374999997), + new Point(302.58984374999994, 276.2109374999997), + new Point(303.5898583815426, 284.3210038050238), + new Point(306.34100306922323, 291.42526150092345), + new Point(308.55078124999994, 299.2578124999997), + new Point(308.55078124999994, 299.2578124999997), + new Point(314.02357444430737, 318.65610875195364), + new Point(312.83820955386796, 338.9193216781303), + new Point(317.41015624999994, 358.4374999999997), + new Point(317.41015624999994, 358.4374999999997), + new Point(324.6448511447705, 389.323263646351), + new Point(341.2272901550544, 419.08257022687917), + new Point(351.55468749999994, 449.3085937499997), + new Point(351.55468749999994, 449.3085937499997), + new Point(354.4485190828321, 457.7782031368645), + new Point(359.85272292551673, 488.59621490807643), + new Point(368.55859374999994, 492.7578124999997), + new Point(368.55859374999994, 492.7578124999997), + new Point(368.9336613544369, 492.9371030581646), + new Point(375.30018285197116, 475.54269522741924), + new Point(385.01171874999994, 460.68749999999966), + new Point(385.01171874999994, 460.68749999999966), + new Point(409.01141338031505, 423.9765046563952), + new Point(465.73402430232653, 338.122252279478), + new Point(470.49609374999994, 336.8945312499997), + new Point(470.49609374999994, 336.8945312499997), + new Point(472.34967396580504, 336.41665510061245), + new Point(470.5375229924171, 340.7226912215484), + new Point(470.56249999999994, 342.6367187499997), + new Point(470.56249999999994, 342.6367187499997), + new Point(470.6277554579174, 347.63734752514455), + new Point(471.4666087447205, 352.597933700578), + new Point(472.79687499999994, 357.4218749999997), + new Point(472.79687499999994, 357.4218749999997), + new Point(478.7003095537336, 378.82948542322754), + new Point(492.1754046938961, 397.52358353298115), + new Point(497.80468749999994, 418.6796874999997), + new Point(497.80468749999994, 418.6796874999997), + new Point(499.2975220287686, 424.29009358262533), + new Point(498.6576561843205, 452.5736061983319), + new Point(502.21874999999994, 455.3749999999997), + new Point(502.21874999999994, 455.3749999999997), + new Point(502.3599404176782, 455.4860697952399), + new Point(526.9859878583989, 412.7902963819643), + new Point(528.28515625, 410.5507812499997), + new Point(528.28515625, 410.5507812499997), + new Point(534.3674131478522, 400.0661462732759), + new Point(586.26953125, 311.2520380124085), + new Point(586.26953125, 306.8515624999997), + ]) + ) + ); + this.Multistrokes.push(new Multistroke(Gestures.RightAngle, useBoundedRotationInvariance, new Array([new Point(200, 0), new Point(0, 0), new Point(0, 100)]))); NumMultistrokes = this.Multistrokes.length; // NumMultistrokes flags the end of the non user-defined gstures strokes // // PREDEFINED STROKES -- cgit v1.2.3-70-g09d2 From 3e1ef3d0b5445065ab3f44ffc17bbb04efaa8c8a Mon Sep 17 00:00:00 2001 From: eleanor-park Date: Tue, 23 Jul 2024 12:07:53 -0400 Subject: merging w/ zach's branch --- src/.DS_Store | Bin 10244 -> 10244 bytes src/client/documents/DocumentTypes.ts | 1 + src/client/util/CurrentUserUtils.ts | 1 + src/client/views/DocumentButtonBar.tsx | 12 +- src/client/views/LightboxView.tsx | 13 +- src/client/views/MainView.tsx | 2 + .../collectionFreeForm/CollectionFreeFormView.tsx | 50 +-- src/client/views/smartdraw/AnnotationPalette.tsx | 370 ++++++++++++++------- src/client/views/smartdraw/SmartDrawHandler.tsx | 97 +++--- 9 files changed, 360 insertions(+), 186 deletions(-) (limited to 'src/client/views/MainView.tsx') diff --git a/src/.DS_Store b/src/.DS_Store index 75cff7b55..d7a0cd9d4 100644 Binary files a/src/.DS_Store and b/src/.DS_Store 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: '' 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: "" 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 { * @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 { 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 { )} {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 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 { 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 { - 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(); @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,8 +51,40 @@ 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; @@ -60,31 +92,55 @@ export class AnnotationPalette extends ObservableReactComponent<{}> { @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 ( - // - // ); + 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(res => setTimeout(() => res(ImageCast(docView.Document.icon)), 1000)); + } + return undefined; + } + + @computed get drawingCreator() { + return ( + + ); + } 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} />