diff options
author | eleanor-park <eleanor_park@brown.edu> | 2024-07-25 23:36:52 -0400 |
---|---|---|
committer | eleanor-park <eleanor_park@brown.edu> | 2024-07-25 23:36:52 -0400 |
commit | 8ca26551622d36b7856f5c1865498fa9e5d888b5 (patch) | |
tree | 51521faf3dc5d1ebcf867d78e7938bbef8135e86 /src | |
parent | a763c4e80cec6aef5219a8c9fcfa2ddccbc10b0a (diff) |
cleaned up smart draw & palette
Diffstat (limited to 'src')
-rw-r--r-- | src/.DS_Store | bin | 14340 -> 14340 bytes | |||
-rw-r--r-- | src/client/documents/Documents.ts | 4 | ||||
-rw-r--r-- | src/client/util/CurrentUserUtils.ts | 3 | ||||
-rw-r--r-- | src/client/util/bezierFit.ts | 2 | ||||
-rw-r--r-- | src/client/views/DocumentButtonBar.tsx | 13 | ||||
-rw-r--r-- | src/client/views/ViewBoxInterface.ts | 2 | ||||
-rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 8 | ||||
-rw-r--r-- | src/client/views/smartdraw/AnnotationPalette.tsx | 80 | ||||
-rw-r--r-- | src/client/views/smartdraw/SmartDrawHandler.tsx | 47 |
9 files changed, 83 insertions, 76 deletions
diff --git a/src/.DS_Store b/src/.DS_Store Binary files differindex 19eea5fce..9130ba97c 100644 --- a/src/.DS_Store +++ b/src/.DS_Store diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index ff95e38bd..d311ad971 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1009,6 +1009,10 @@ export namespace Docs { return InstanceFromProto(Prototypes.get(DocumentType.DATAVIZ), new CsvField(url), { title: 'Data Viz', type: 'dataviz', ...options }, undefined, undefined, undefined, overwriteDoc); } + export function AnnoPaletteDocument(options?: DocumentOptions) { + return InstanceFromProto(Prototypes.get(DocumentType.ANNOPALETTE), new List([Doc.MyAnnos]), { ...(options || {}) }); + } + export function DockDocument(documents: Array<Doc>, config: string, options: DocumentOptions, id?: string) { const ret = InstanceFromProto(Prototypes.get(DocumentType.COL), new List(documents), { treeView_FreezeChildren: 'remove|add', ...options, type_collection: CollectionViewType.Docking, dockingConfig: config }, id); documents.map(c => Doc.SetContainer(c, ret)); diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index 6b59828eb..8c7d40158 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -176,7 +176,7 @@ export class CurrentUserUtils { static setupLightboxDrawingPreviews(doc: Doc, field="myLightboxDrawings") { const reqdOpts:DocumentOptions = { - title: "Preview", _layout_fitWidth: true, childLayoutFitWidth: true, + title: "Preview", _header_height: 0, _layout_fitWidth: true, childLayoutFitWidth: true, }; const reqdScripts = {}; const drawings = DocCast(doc[field]); @@ -392,6 +392,7 @@ pie title Minerals in my tap water {key: "Script", creator: opts => Docs.Create.ScriptingDocument(null, opts), opts: { _width: 200, _height: 250, }}, {key: "DataViz", creator: opts => Docs.Create.DataVizDocument("/users/rz/Downloads/addresses.csv", opts), opts: { _width: 300, _height: 300 }}, {key: "Chat", creator: Docs.Create.ChatDocument, opts: { _width: 300, _height: 300, }}, + {key: "AnnoPalette",creator: Docs.Create.AnnoPaletteDocument, opts: {_width: 300, _height: 300, _dropAction: dropActionType.move }}, {key: "Header", creator: headerTemplate, opts: { _width: 300, _height: 120, _header_pointerEvents: "all", _header_height: 50, _header_fontSize: 9,_layout_autoHeightMargins: 50, _layout_autoHeight: true, treeView_HideUnrendered: true}}, {key: "ViewSlide", creator: slideView, opts: { _width: 400, _height: 300, _xMargin: 3, _yMargin: 3,}}, {key: "Trail", creator: Docs.Create.PresDocument, opts: { _width: 400, _height: 30, _type_collection: CollectionViewType.Stacking, dropAction: dropActionType.embed, treeView_HideTitle: true, _layout_fitWidth:true, layout_boxShadow: "0 0" }}, diff --git a/src/client/util/bezierFit.ts b/src/client/util/bezierFit.ts index 6a4577506..693676bc3 100644 --- a/src/client/util/bezierFit.ts +++ b/src/client/util/bezierFit.ts @@ -694,7 +694,7 @@ export function SVGToBezier(name: SVGType, attributes: any): Point[] { const matches: RegExpMatchArray[] = Array.from( attributes.d.matchAll(/Q(-?\d+\.?\d*),(-?\d+\.?\d*) (-?\d+\.?\d*),(-?\d+\.?\d*)|C(-?\d+\.?\d*),(-?\d+\.?\d*) (-?\d+\.?\d*),(-?\d+\.?\d*) (-?\d+\.?\d*),(-?\d+\.?\d*)|L(-?\d+\.?\d*),(-?\d+\.?\d*)/g) ); - let lastPt: Point = { X: 0, Y: 0 }; + let lastPt: Point; matches.forEach(match => { if (match[0].startsWith('Q')) { coordList.push({ X: parseInt(match[1]), Y: parseInt(match[2]) }); diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 6950bec14..15e90ac2a 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -243,23 +243,18 @@ export class DocumentButtonBar extends ObservableReactComponent<{ views: () => ( ); } - @observable _annoSaved: boolean = false; - @undoBatch - saveAnno = action((targetDoc: Doc) => { - // targetDoc.savedAsAnno = true; - this._annoSaved = true; - // AnnotationPalette.addToPalette(targetDoc); + saveAnno = action(async (targetDoc: Doc) => { + await AnnotationPalette.addToPalette(targetDoc); }); @computed get saveAnnoButton() { const targetDoc = this.view0?.Document; - if (targetDoc && targetDoc.savedAsAnno) this._annoSaved = true; return !targetDoc ? null : ( - <Tooltip title={<div className="dash-tooltip">{this._annoSaved ? 'Saved as Annotation!' : 'Save to Annotation Palette'}</div>}> + <Tooltip title={<div className="dash-tooltip">{targetDoc.savedAsAnno ? 'Saved as Annotation!' : 'Save to Annotation Palette'}</div>}> <div className="documentButtonBar-icon" style={{ color: 'white' }} onClick={() => this.saveAnno(targetDoc)}> - <FontAwesomeIcon className="documentdecorations-icon" icon={this._annoSaved ? 'clipboard-check' : 'file-arrow-down'} /> + <FontAwesomeIcon className="documentdecorations-icon" icon={targetDoc.savedAsAnno ? 'clipboard-check' : 'file-arrow-down'} /> </div> </Tooltip> ); diff --git a/src/client/views/ViewBoxInterface.ts b/src/client/views/ViewBoxInterface.ts index c633f34fb..ea5f3dd27 100644 --- a/src/client/views/ViewBoxInterface.ts +++ b/src/client/views/ViewBoxInterface.ts @@ -19,7 +19,7 @@ export abstract class ViewBoxInterface<P> extends ObservableReactComponent<React abstract get dataDoc(): Doc; abstract get fieldKey(): string; promoteCollection?: () => void; // moves contents of collection to parent - updateIcon?: () => void; // updates the icon representation of the document + updateIcon?: (usePanelDimensions?: boolean) => void; // updates the icon representation of the document getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box) restoreView?: (viewSpec: Doc) => boolean; scrollPreview?: (docView: DocumentView, doc: Doc, focusSpeed: number, options: FocusViewOptions) => Opt<number>; // returns the duration of the focus diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index f2b94fabc..a298e6ac4 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1301,7 +1301,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection _height: B.height + inkWidth, stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore inkWidth, - stroke[1], + opts.autoColor ? stroke[1] : ActiveInkColor(), ActiveInkBezierApprox(), stroke[2] === 'none' ? ActiveFillColor() : stroke[2], ActiveArrowStart(), @@ -1911,12 +1911,12 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection Object.values(this._disposers).forEach(disposer => disposer?.()); } - updateIcon = () => + updateIcon = (usePanelDimensions?: boolean) => UpdateIcon( this.layoutDoc[Id] + '-icon' + new Date().getTime(), this.DocumentView?.().ContentDiv!, - NumCast(this.layoutDoc._width), - NumCast(this.layoutDoc._height), + usePanelDimensions ? this._props.PanelWidth() : NumCast(this.layoutDoc._width), + usePanelDimensions ? this._props.PanelHeight() : NumCast(this.layoutDoc._height), this._props.PanelWidth(), this._props.PanelHeight(), 0, diff --git a/src/client/views/smartdraw/AnnotationPalette.tsx b/src/client/views/smartdraw/AnnotationPalette.tsx index 83f173fcb..ec4279e3e 100644 --- a/src/client/views/smartdraw/AnnotationPalette.tsx +++ b/src/client/views/smartdraw/AnnotationPalette.tsx @@ -11,7 +11,7 @@ import { returnAll, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnOn import { ActiveInkWidth, Doc, DocListCast, Opt, StrListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { InkData, InkField } from '../../../fields/InkField'; -import { BoolCast, DocCast, ImageCast, NumCast } from '../../../fields/Types'; +import { BoolCast, DocCast, ImageCast } from '../../../fields/Types'; import { emptyFunction, unimplementedFunction } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { makeUserTemplateButton, makeUserTemplateImage } from '../../util/DropConverter'; @@ -19,7 +19,7 @@ import { SettingsManager } from '../../util/SettingsManager'; import { Transform } from '../../util/Transform'; 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 { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveIsInkMask, DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; import { FieldView } from '../nodes/FieldView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { DefaultStyleProvider } from '../StyleProvider'; @@ -30,9 +30,12 @@ import { ImageField } from '../../../fields/URLField'; import { CollectionCarousel3DView } from '../collections/CollectionCarousel3DView'; import { Copy } from '../../../fields/FieldSymbols'; +interface AnnotationPaletteProps { + Document: Doc; +} + @observer -export class AnnotationPalette extends ObservableReactComponent<{ Document: Doc }> { - static Instance: AnnotationPalette; +export class AnnotationPalette extends ObservableReactComponent<AnnotationPaletteProps> { @observable private _paletteMode: 'create' | 'view' = 'view'; @observable private _userInput: string = ''; @observable private _isLoading: boolean = false; @@ -46,7 +49,6 @@ export class AnnotationPalette extends ObservableReactComponent<{ Document: Doc constructor(props: any) { super(props); makeObservable(this); - AnnotationPalette.Instance = this; } public static LayoutString(fieldKey: string) { @@ -102,30 +104,35 @@ export class AnnotationPalette extends ObservableReactComponent<{ Document: Doc this._canInteract = true; this._opts = { text: '', complexity: 5, size: 200, autoColor: true, x: 0, y: 0 }; this._gptRes = []; + this._props.Document[DocData].data = undefined; }; public static addToPalette = async (doc: Doc) => { - // if (!doc.savedAsAnno) { - // const clone = await Doc.MakeClone(doc); - // clone.clone.title = doc.title; - // const image = (await this.getIcon(doc))?.[Copy](); - // if (image) { - // const imageTemplate = makeUserTemplateImage(clone.clone, image); - // Doc.AddDocToList(Doc.MyAnnos, 'data', imageTemplate); - // doc.savedAsAnno = true; - // } - // this.resetPalette(true); - // } + if (!doc.savedAsAnno) { + const clone = await Doc.MakeClone(doc); + clone.clone.title = doc.title; + const image = (await AnnotationPalette.getIcon(doc))?.[Copy](); + if (image) { + const imageTemplate = makeUserTemplateImage(clone.clone, image); + Doc.AddDocToList(Doc.MyAnnos, 'data', imageTemplate); + doc.savedAsAnno = true; + } + } }; - // @action - // displayPalette = (display: boolean) => { - // this._display = display; - // }; + public static getIcon(group: Doc) { + const docView = DocumentView.getDocumentView(group); + if (docView) { + docView.ComponentView?.updateIcon?.(true); + return new Promise<ImageField | undefined>(res => setTimeout(() => res(ImageCast(docView.Document.icon)), 1000)); + } + return undefined; + } @undoBatch generateDrawing = action(async () => { this._isLoading = true; + this._props.Document[DocData].data = undefined; for (var i = 0; i < 3; i++) { try { SmartDrawHandler.Instance._addFunc = this.createDrawing; @@ -154,7 +161,7 @@ export class AnnotationPalette extends ObservableReactComponent<{ Document: Doc strokeList.forEach((stroke: [InkData, string, string]) => { const bounds = InkField.getBounds(stroke[0]); - const inkWidth = ActiveInkWidth(); + const inkWidth = Math.min(5, ActiveInkWidth()); const inkDoc = Docs.Create.InkDocument( stroke[0], { title: 'stroke', @@ -164,7 +171,7 @@ export class AnnotationPalette extends ObservableReactComponent<{ Document: Doc _height: bounds.height + inkWidth, stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore inkWidth, - stroke[1], + opts.autoColor ? stroke[1] : ActiveInkColor(), ActiveInkBezierApprox(), stroke[2] === 'none' ? ActiveFillColor() : stroke[2], ActiveArrowStart(), @@ -177,28 +184,30 @@ export class AnnotationPalette extends ObservableReactComponent<{ Document: Doc const collection = MarqueeView.getCollection(drawing, undefined, true, { left: 1, top: 1, width: 1, height: 1 }); if (collection) { + collection[DocData].freeform_fitContentsToBox = true; Doc.AddDocToList(this._props.Document, 'data', collection); } }; saveDrawing = async () => { - // 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; - // await AnnotationPalette.addToPalette(focusedDrawing); + const cIndex: number = this._props.Document.carousel_index as number; + const focusedDrawing = DocListCast(this._props.Document.data)[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; + await AnnotationPalette.addToPalette(focusedDrawing); + this.resetPalette(true); }; async getIcon(group: Doc) { const docView = DocumentView.getDocumentView(group); if (docView) { - docView.ComponentView?.updateIcon?.(); + docView.ComponentView?.updateIcon?.(true); return new Promise<ImageField | undefined>(res => setTimeout(() => res(ImageCast(docView.Document.icon)), 1000)); } return undefined; @@ -206,7 +215,7 @@ export class AnnotationPalette extends ObservableReactComponent<{ Document: Doc render() { return ( - <div className="annotation-palette" style={{ zIndex: 1000 }}> + <div className="annotation-palette" style={{ zIndex: 1000 }} onClick={e => e.stopPropagation()}> {this._paletteMode === 'view' && ( <> <DocumentView @@ -241,7 +250,6 @@ export class AnnotationPalette extends ObservableReactComponent<{ Document: Doc type="text" style={{ color: 'black', width: '170px' }} value={this._userInput} - onClick={e => e.stopPropagation()} onChange={e => { this.setUserInput(e.target.value); }} diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx index ca65ea388..c842551c3 100644 --- a/src/client/views/smartdraw/SmartDrawHandler.tsx +++ b/src/client/views/smartdraw/SmartDrawHandler.tsx @@ -51,6 +51,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { private _lastInput: DrawingOptions = { text: '', complexity: 5, size: 350, autoColor: true, x: 0, y: 0 }; private _lastResponse: string = ''; private _selectedDoc: Doc | undefined = undefined; + private _errorOccurredOnce = false; constructor(props: any) { super(props); @@ -152,39 +153,37 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { this._showEditBox = false; } else { this._showOptions = false; - await this.drawWithGPT({ X: this._pageX, Y: this._pageY }, this._userInput, this._complexity, this._size, this._autoColor); + try { + await this.drawWithGPT({ X: this._pageX, Y: this._pageY }, this._userInput, this._complexity, this._size, this._autoColor); + this._showRegenerate = true; + this.hideSmartDrawHandler(); + } catch (err) { + if (this._errorOccurredOnce) { + console.error('GPT call failed', err); + this._errorOccurredOnce = false; + } else { + this._errorOccurredOnce = true; + await this.drawWithGPT({ X: this._pageX, Y: this._pageY }, this._userInput, this._complexity, this._size, this._autoColor); + } + } } 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}", "${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, autoColor); - this._errorOccurredOnce = false; - this.hideSmartDrawHandler(); - this._showRegenerate = true; - return strokeData; - } catch (err) { - if (this._errorOccurredOnce) { - console.error('GPT call failed', err); - this._errorOccurredOnce = false; - } else { - this._errorOccurredOnce = true; - this.drawWithGPT(startPt, input, complexity, size, autoColor); - } + 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, autoColor); + this._errorOccurredOnce = false; + return strokeData; }; @action @@ -212,7 +211,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { return; } console.log(res); - this.parseResponse(res, { X: this._lastInput.x, Y: this._lastInput.y }, true, lastInput?.autoColor || this._autoColor); + await this.parseResponse(res, { X: this._lastInput.x, Y: this._lastInput.y }, true, lastInput?.autoColor || this._autoColor); } catch (err) { console.error('GPT call failed', err); } |