From 49b3c7cbe01f830a2b1d2c02452901fe360348d3 Mon Sep 17 00:00:00 2001
From: eleanor-park <eleanor_park@brown.edu>
Date: Thu, 11 Jul 2024 11:50:01 -0400
Subject: updates

---
 src/client/views/smartdraw/SmartDrawHandler.tsx | 95 +++++++++++++++----------
 1 file changed, 59 insertions(+), 36 deletions(-)

(limited to 'src/client/views/smartdraw/SmartDrawHandler.tsx')

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<Element>, 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<Element>, 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<Element>, 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<Element>, 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<Element>) => {
+    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<Element>, res: string, startPoint: { X: number; Y: number }, regenerate: boolean) => {
+    parseResponse = async (res: string, startPoint: { X: number; Y: number }, regenerate: boolean) => {
         const svg = res.match(/<svg[^>]*>([\s\S]*?)<\/svg>/g);
+        console.log(svg);
         console.log('start point is', startPoint);
         if (svg) {
             this._lastResponse = svg[0];
             const svgObject = await parse(svg[0]);
             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 (
                 <div
                     id="label-handler"
-                    className="contextMenu-cont"
+                    className="smart-draw-handler"
                     style={{
                         display: this._display ? '' : 'none',
                         left: this._pageX,
@@ -242,8 +264,9 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
                             style={{ width: '19px' }}
                         />
                         <input
-                            aria-label="label-input"
-                            id="new-label"
+                            aria-label="Smart Draw Input"
+                            className="smartdraw-input"
+                            id="smartdraw-input"
                             type="text"
                             style={{ color: 'black' }}
                             value={this._userInput}
@@ -251,7 +274,9 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
                                 this.setUserInput(e.target.value);
                             }}
                             placeholder="Enter item to draw"
+                            onKeyDown={this.handleKeyPress}
                         />
+                        <IconButton tooltip="Advanced Options" icon={<FontAwesomeIcon icon={this._showOptions ? 'caret-down' : 'caret-right'} />} color={SettingsManager.userColor} style={{ width: '14px' }} onClick={this.setShowOptions} />
                         <Button
                             style={{ alignSelf: 'flex-end' }}
                             text="Send"
@@ -259,7 +284,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
                             iconPlacement="right"
                             color={SettingsManager.userColor}
                             onClick={e => {
-                                this.drawWithGPT(e as React.PointerEvent<Element>, this._userInput);
+                                this.drawWithGPT({ X: e.clientX, Y: e.clientY }, this._userInput);
                             }}
                         />
                     </div>
@@ -349,7 +374,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
             return (
                 <div
                     id="smartdraw-options-menu"
-                    className="contextMenu-cont"
+                    className="smart-draw-handler"
                     style={{
                         left: this._pageX,
                         ...(this._yRelativeToTop ? { top: Math.max(0, this._pageY) } : { bottom: this._pageY }),
@@ -365,9 +390,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
                             tooltip="Regenerate"
                             icon={this._isLoading && this._regenInput === '' ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <FontAwesomeIcon icon={'rotate'} />}
                             color={SettingsManager.userColor}
-                            onClick={e => {
-                                this.regenerate(e as React.PointerEvent<Element>);
-                            }}
+                            onClick={this.regenerate}
                         />
                         <IconButton tooltip="Edit with GPT" icon={<FontAwesomeIcon icon="pen-to-square" />} color={SettingsManager.userColor} onClick={this.edit} />
                         {this._showEditBox && (
@@ -378,6 +401,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
                                 }}>
                                 <input
                                     aria-label="Edit instructions input"
+                                    className="smartdraw-input"
                                     id="regen-input"
                                     type="text"
                                     style={{ color: 'black' }}
@@ -385,6 +409,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
                                     onChange={e => {
                                         this.setRegenInput(e.target.value);
                                     }}
+                                    onKeyDown={this.handleKeyPress}
                                     placeholder="Edit instructions"
                                 />
                                 <Button
@@ -393,9 +418,7 @@ export class SmartDrawHandler extends ObservableReactComponent<{}> {
                                     icon={this._isLoading && this._regenInput !== '' ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <AiOutlineSend />}
                                     iconPlacement="right"
                                     color={SettingsManager.userColor}
-                                    onClick={e => {
-                                        this.regenerate(e as React.PointerEvent<Element>);
-                                    }}
+                                    onClick={this.regenerate}
                                 />
                             </div>
                         )}
-- 
cgit v1.2.3-70-g09d2

