From 4dd32452ad45ce0ed01fe577eb198a99ccd69754 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 29 Aug 2024 22:38:53 -0400 Subject: cleaning up smartDrawHandler --- src/client/util/CurrentUserUtils.ts | 2 - .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/smartdraw/SmartDrawHandler.tsx | 488 ++++++++------------- 3 files changed, 196 insertions(+), 296 deletions(-) (limited to 'src') diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index cdf5505f8..ec8898b93 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -386,7 +386,6 @@ 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" }}, @@ -429,7 +428,6 @@ 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 unknown as Doc, 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/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c0f01383d..76549a423 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -2006,7 +2006,7 @@ export class CollectionFreeFormView extends CollectionSubView { +export class SmartDrawHandler extends ObservableReactComponent { static Instance: SmartDrawHandler; + 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; + @observable private _display: boolean = false; @observable private _pageX: number = 0; @observable private _pageY: number = 0; @@ -47,18 +51,21 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { @observable private _userInput: string = ''; @observable private _showOptions: boolean = false; @observable private _showEditBox: boolean = false; - @observable public _showRegenerate: boolean = false; @observable private _complexity: number = 5; @observable private _size: number = 200; @observable private _autoColor: boolean = true; @observable private _regenInput: string = ''; @observable private _canInteract: boolean = true; - private _lastInput: DrawingOptions = { text: '', complexity: 5, size: 350, autoColor: true, x: 0, y: 0 }; - private _lastResponse: string = ''; - private _selectedDoc: Doc | undefined = undefined; - private _errorOccurredOnce = false; + @observable public ShowRegenerate: boolean = false; + + constructor(props: object) { + super(props); + makeObservable(this); + SmartDrawHandler.Instance = this; + } + public AddDrawing: (doc: Doc, opts: DrawingOptions, gptRes: string) => void = unimplementedFunction; public RemoveDrawing: (doc?: Doc) => void = unimplementedFunction; public CreateDrawingDoc: (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => Doc | undefined = (strokeList: [InkData, string, string][], opts: DrawingOptions) => { const drawing: Doc[] = []; @@ -85,67 +92,21 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { drawing.push(inkDoc); }); - const collection = MarqueeView.getCollection(drawing, undefined, true, { left: 1, top: 1, width: 1, height: 1 }); - return collection; - }; - public AddDrawing: (doc: Doc, opts: DrawingOptions, gptRes: string) => void = unimplementedFunction; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - constructor(props: any) { - super(props); - makeObservable(this); - SmartDrawHandler.Instance = this; - } - - @action - setUserInput = (input: string) => { - if (this._canInteract) this._userInput = input; - }; - - @action - setRegenInput = (input: string) => { - if (this._canInteract) this._regenInput = input; - }; - - @action - setShowOptions = () => { - this._showOptions = !this._showOptions; - }; - - @action - setComplexity = (val: number) => { - if (this._canInteract) this._complexity = val; - }; - - @action - setSize = (val: number) => { - if (this._canInteract) this._size = val; - }; - - @action - setAutoColor = () => { - if (this._canInteract) this._autoColor = !this._autoColor; - }; - - @action - setEdit = () => { - this._showEditBox = !this._showEditBox; + return MarqueeView.getCollection(drawing, undefined, true, { left: 1, top: 1, width: 1, height: 1 }); }; @action displaySmartDrawHandler = (x: number, y: number) => { - this._pageX = x; - this._pageY = y; + [this._pageX, this._pageY] = [x, y]; this._display = true; }; @action displayRegenerate = (x: number, y: number) => { this._selectedDoc = DocumentView.SelectedDocs()?.lastElement(); - this._pageX = x; - this._pageY = y; + [this._pageX, this._pageY] = [x, y]; this._display = false; - this._showRegenerate = true; + this.ShowRegenerate = true; this._showEditBox = false; const docData = this._selectedDoc[DocData]; this._lastResponse = StrCast(docData.drawingData); @@ -154,7 +115,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { @action hideSmartDrawHandler = () => { - this._showRegenerate = false; + this.ShowRegenerate = false; this._display = false; this._isLoading = false; this._showOptions = false; @@ -168,17 +129,16 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { @action hideRegenerate = () => { if (!this._isLoading) { - this._showRegenerate = false; + this.ShowRegenerate = false; this._isLoading = false; this._regenInput = ''; this._lastInput = { text: '', complexity: 5, size: 350, autoColor: true, x: 0, y: 0 }; } }; - @action - handleKeyPress = async (event: React.KeyboardEvent) => { + handleKeyPress = (event: React.KeyboardEvent) => { if (event.key === 'Enter') { - await this.handleSendClick(); + this.handleSendClick(); } }; @@ -186,7 +146,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { handleSendClick = async () => { this._isLoading = true; this._canInteract = false; - if (this._showRegenerate) { + if (this.ShowRegenerate) { await this.regenerate(); this._regenInput = ''; this._showEditBox = false; @@ -195,7 +155,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { try { await this.drawWithGPT({ X: this._pageX, Y: this._pageY }, this._userInput, this._complexity, this._size, this._autoColor); this.hideSmartDrawHandler(); - this._showRegenerate = true; + this.ShowRegenerate = true; } catch (err) { if (this._errorOccurredOnce) { console.error('GPT call failed', err); @@ -222,10 +182,8 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { console.error('GPT call failed'); return; } - console.log(res); const strokeData = await this.parseSvg(res, startPt, false, autoColor); const drawingDoc = strokeData && this.CreateDrawingDoc(strokeData?.data, strokeData?.lastInput, strokeData?.lastRes); - // eslint-disable-next-line @typescript-eslint/no-unused-expressions drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, res); this._errorOccurredOnce = false; @@ -254,12 +212,9 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { console.error('GPT call failed'); return; } - console.log(res); const strokeData = await this.parseSvg(res, { X: this._lastInput.x, Y: this._lastInput.y }, true, lastInput?.autoColor || this._autoColor); - // eslint-disable-next-line @typescript-eslint/no-unused-expressions this.RemoveDrawing !== unimplementedFunction && this.RemoveDrawing(this._selectedDoc); const drawingDoc = strokeData && this.CreateDrawingDoc(strokeData?.data, strokeData?.lastInput, strokeData?.lastRes); - // eslint-disable-next-line @typescript-eslint/no-unused-expressions drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, res); return strokeData; } catch (err) { @@ -278,13 +233,10 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { const svgObject = await parse(svg[0]); const svgStrokes: INode[] = svgObject.children; const strokeData: [InkData, string, string][] = []; - // eslint-disable-next-line @typescript-eslint/no-explicit-any svgStrokes.forEach(child => { const convertedBezier: InkData = SVGToBezier(child.name as SVGType, child.attributes); strokeData.push([ - convertedBezier.map(point => { - return { X: point.X + startPoint.X - this._size / 1.5, Y: point.Y + startPoint.Y - this._size / 2 }; - }), + convertedBezier.map(point => ({ X: point.X + startPoint.X - this._size / 1.5, Y: point.Y + startPoint.Y - this._size / 2 })), (regenerate ? this._lastInput.autoColor : autoColor) ? child.attributes.stroke : '', (regenerate ? this._lastInput.autoColor : autoColor) ? child.attributes.fill : '', ]); @@ -298,7 +250,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { */ colorWithGPT = async (drawing: Doc) => { const img = await this.getIcon(drawing); - const { href } = (img as URLField).url; + const { href } = ImageCast(img).url; const hrefParts = href.split('.'); const hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`; try { @@ -308,20 +260,9 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { strokes.forEach((stroke, i) => { const inkingStroke = DocumentView.getDocumentView(stroke)?.ComponentView as InkingStroke; const { inkData } = inkingStroke.inkScaledData(); - coords.push( - `${i + 1}. ${inkData - .filter((point, index) => { - return index % 4 === 0 || index == inkData.length - 1; - }) - .map(point => { - return `(${point.X.toString()}, ${point.Y.toString()})`; - })}` - ); + coords.push(`${i + 1}. ${inkData.filter((point, index) => index % 4 === 0 || index == inkData.length - 1).map(point => `(${point.X.toString()}, ${point.Y.toString()})`)}`); }); - const response = await gptDrawingColor(hrefBase64, coords); - console.log(response); - const colorResponse = await gptAPICall(response, GPTCallType.COLOR, undefined); - console.log(colorResponse); + const colorResponse = await gptDrawingColor(hrefBase64, coords).then(response => gptAPICall(response, GPTCallType.COLOR, undefined)); this.colorStrokes(colorResponse, drawing); } catch (error) { console.log('GPT call failed', error); @@ -331,8 +272,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { /** * Function that parses the GPT color response and sets the selected stroke(s) to the new color. */ - @undoBatch - colorStrokes = (res: string, drawing: Doc) => { + colorStrokes = undoable((res: string, drawing: Doc) => { const colorList = res.match(/\{.*?\}/g); const strokes = DocListCast(drawing[DocData].data); colorList?.forEach((colors, index) => { @@ -341,213 +281,175 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> { strokes[index][DocData].color = strokeAndFill[0]; const inkStroke = DocumentView.getDocumentView(strokes[index])?.ComponentView as InkingStroke; const { inkData } = inkStroke.inkScaledData(); - // eslint-disable-next-line @typescript-eslint/no-unused-expressions InkingStroke.IsClosed(inkData) ? (strokes[index][DocData].fillColor = strokeAndFill[1]) : (strokes[index][DocData].fillColor = undefined); } }); - }; + }, 'color strokes'); /** * Gets an image snapshot of a doc. In this class, it's used to snapshot a selected ink stroke/group to use for GPT color. */ async getIcon(doc: Doc) { const docView = DocumentView.getDocumentView(doc); - console.log(doc); if (docView) { - console.log(docView); docView.ComponentView?.updateIcon?.(); return new Promise(res => setTimeout(() => res(ImageCast(docView.Document.icon)), 1000)); } return undefined; } - render() { - if (this._display) { - return ( -
-
- { - this.hideSmartDrawHandler(); - this.hideRegenerate(); - }} - icon={} - color={SettingsManager.userColor} - 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} /> -
- {this._showOptions && ( - <> -
-
- Auto color - -
-
- Complexity - { - this.setComplexity(val as number); - }} - valueLabelDisplay="auto" - /> -
-
- Size (in pixels) - { - this.setSize(val as number); - }} - valueLabelDisplay="auto" - /> -
-
- - )} + renderDisplay() { + return ( +
+
+ { + this.hideSmartDrawHandler(); + this.hideRegenerate(); + }} + icon={} + color={SettingsManager.userColor} + style={{ width: '19px' }} + /> + this._canInteract && (this._userInput = e.target.value))} + placeholder="Enter item to draw" + onKeyDown={this.handleKeyPress} + /> + } + color={SettingsManager.userColor} + style={{ width: '14px' }} + onClick={action(() => (this._showOptions = !this._showOptions))} + /> +
- ); - } else if (this._showRegenerate) { - return ( -
-
- : } - color={SettingsManager.userColor} - onClick={this.handleSendClick} - /> - } color={SettingsManager.userColor} onClick={this.setEdit} /> - {this._showEditBox && ( -
- { - this.setRegenInput(e.target.value); - }} - onKeyDown={this.handleKeyPress} - placeholder="Edit instructions" - /> -
- )} + {this._showOptions && ( +
+
+ Auto color + this._canInteract && (this._autoColor = !this._autoColor))} + /> +
+
+ Complexity + this._canInteract && (this._complexity = val as number))} + valueLabelDisplay="auto" + /> +
+
+ Size (in pixels) + this._canInteract && (this._size = val as number))} + valueLabelDisplay="auto" + /> +
+ )} +
+ ); + } + + renderRegenerate() { + return ( +
+
+ : } + color={SettingsManager.userColor} + onClick={this.handleSendClick} + /> + } color={SettingsManager.userColor} onClick={action(() => (this._showEditBox = !this._showEditBox))} /> + {this._showEditBox && ( +
+ this._canInteract && (this._regenInput = e.target.value))} + onKeyDown={this.handleKeyPress} + placeholder="Edit instructions" + /> +
+ )}
- ); - } else { - return <>; - } +
+ ); + } + + render() { + return this._display ? this.renderDisplay() : this.ShowRegenerate ? this.renderRegenerate() : null; } } -- cgit v1.2.3-70-g09d2