import { faLaptopHouse } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Slider, Switch } from '@mui/material'; import { Button, IconButton } from 'browndash-components'; 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, DocListCast, Opt, StrListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { InkData, InkField } from '../../../fields/InkField'; import { BoolCast, DocCast, ImageCast } from '../../../fields/Types'; import { emptyFunction, unimplementedFunction } from '../../../Utils'; import { Docs } from '../../documents/Documents'; import { makeUserTemplateButton, makeUserTemplateImage } from '../../util/DropConverter'; 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, ActiveInkColor, ActiveIsInkMask, DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; import { FieldView } from '../nodes/FieldView'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { DefaultStyleProvider } from '../StyleProvider'; import './AnnotationPalette.scss'; import { DrawingOptions, SmartDrawHandler } from './SmartDrawHandler'; import { DocumentType } from '../../documents/DocumentTypes'; 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 { @observable private _paletteMode: 'create' | 'view' = 'view'; @observable private _userInput: string = ''; @observable private _isLoading: boolean = false; @observable private _canInteract: boolean = true; @observable private _showRegenerate: boolean = false; @observable private _docView: DocumentView | null = null; @observable private _docCarouselView: DocumentView | null = null; @observable private _opts: DrawingOptions = { text: '', complexity: 5, size: 200, autoColor: true, x: 0, y: 0 }; private _gptRes: string[] = []; constructor(props: any) { super(props); makeObservable(this); } public static LayoutString(fieldKey: string) { return FieldView.LayoutString(AnnotationPalette, fieldKey); } Contains = (view: DocumentView) => { return (this._docView && (view.containerViewPath?.() ?? []).concat(view).includes(this._docView)) || (this._docCarouselView && (view.containerViewPath?.() ?? []).concat(view).includes(this._docCarouselView)); }; return170 = () => 170; @action handleKeyPress = async (event: React.KeyboardEvent) => { if (event.key === 'Enter') { await this.generateDrawing(); } }; @action setPaletteMode = (mode: 'create' | 'view') => { this._paletteMode = mode; }; @action setUserInput = (input: string) => { if (!this._isLoading) this._userInput = input; }; @action setDetail = (detail: number) => { if (this._canInteract) this._opts.complexity = detail; }; @action setColor = (autoColor: boolean) => { if (this._canInteract) this._opts.autoColor = autoColor; }; @action setSize = (size: number) => { if (this._canInteract) this._opts.size = size; }; @action resetPalette = (changePaletteMode: boolean) => { if (changePaletteMode) this.setPaletteMode('view'); this.setUserInput(''); this.setDetail(5); this.setColor(true); this.setSize(200); this._showRegenerate = false; 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 AnnotationPalette.getIcon(doc))?.[Copy](); if (image) { const imageTemplate = makeUserTemplateImage(clone.clone, image); Doc.AddDocToList(Doc.MyAnnos, 'data', imageTemplate); doc.savedAsAnno = true; } } }; public static getIcon(group: Doc) { const docView = DocumentView.getDocumentView(group); if (docView) { docView.ComponentView?.updateIcon?.(true); return new Promise(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; 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._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); const drawing: Doc[] = []; strokeList.forEach((stroke: [InkData, string, string]) => { const bounds = InkField.getBounds(stroke[0]); const inkWidth = Math.min(5, 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, opts.autoColor ? stroke[1] : ActiveInkColor(), ActiveInkBezierApprox(), stroke[2] === 'none' ? ActiveFillColor() : stroke[2], ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), ActiveIsInkMask() ); drawing.push(inkDoc); }); 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._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?.(true); return new Promise(res => setTimeout(() => res(ImageCast(docView.Document.icon)), 1000)); } return undefined; } render() { return (
e.stopPropagation()}> {this._paletteMode === 'view' && ( <> (this._docView = r)} Document={Doc.MyAnnos} 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} />
Color this.setColor(!this._opts.autoColor)} />
Detail { this.setDetail(val as number); }} valueLabelDisplay="auto" />
Size { this.setSize(val as number); }} valueLabelDisplay="auto" />
(this._docCarouselView = r)} Document={this._props.Document} 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} />
)} ); } } Docs.Prototypes.TemplateMap.set(DocumentType.ANNOPALETTE, { layout: { view: AnnotationPalette, dataField: 'data' }, options: { acl: '' }, });