aboutsummaryrefslogtreecommitdiff
path: root/src/client/views
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views')
-rw-r--r--src/client/views/collections/CollectionSubView.tsx17
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx36
-rw-r--r--src/client/views/pdf/AnchorMenu.tsx2
-rw-r--r--src/client/views/smartdraw/SmartDrawHandler.tsx72
4 files changed, 58 insertions, 69 deletions
diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx
index ca830aa6f..655894e40 100644
--- a/src/client/views/collections/CollectionSubView.tsx
+++ b/src/client/views/collections/CollectionSubView.tsx
@@ -541,12 +541,17 @@ export function CollectionSubView<X>() {
DocUtils.uploadYoutubeVideoLoading(files, {}, loading);
} else {
generatedDocuments.push(
- ...files.map(file => {
- const loading = Docs.Create.LoadingDocument(file, options);
- Doc.addCurrentlyLoading(loading);
- DocUtils.uploadFileToDoc(file, {}, loading);
- return loading;
- })
+ ...(await Promise.all(
+ files.map(async file => {
+ if (file.name.endsWith('svg')) {
+ return (await DocUtils.openSVGfile(file, options)) as Doc;
+ }
+ const loading = Docs.Create.LoadingDocument(file, options);
+ Doc.addCurrentlyLoading(loading);
+ DocUtils.uploadFileToDoc(file, {}, loading);
+ return loading;
+ })
+ ))
);
}
if (generatedDocuments.length) {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index aa9b9b0fa..b3d908da4 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -30,7 +30,7 @@ import { CompileScript } from '../../../util/Scripting';
import { ScriptingGlobals } from '../../../util/ScriptingGlobals';
import { freeformScrollMode, SnappingManager } from '../../../util/SnappingManager';
import { Transform } from '../../../util/Transform';
-import { undoable, undoBatch, UndoManager } from '../../../util/UndoManager';
+import { undoable, UndoManager } from '../../../util/UndoManager';
import { Timeline } from '../../animationtimeline/Timeline';
import { ContextMenu } from '../../ContextMenu';
import { InkingStroke } from '../../InkingStroke';
@@ -1232,7 +1232,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
showSmartDraw = (x: number, y: number, regenerate?: boolean) => {
const sm = SmartDrawHandler.Instance;
- sm.CreateDrawingDoc = this.createDrawingDoc;
sm.RemoveDrawing = this.removeDrawing;
sm.AddDrawing = this.addDrawing;
(regenerate ? sm.displayRegenerate : sm.displaySmartDrawHandler)(x, y, NumCast(this.layoutDoc[this.scaleFieldKey]));
@@ -1240,38 +1239,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
_drawing: Doc[] = [];
_drawingContainer: Doc | undefined = undefined;
- /**
- * Function that creates a drawing--a group of ink strokes--to go with the smart draw function.
- */
- @undoBatch
- createDrawingDoc = (strokeData: [InkData, string, string][], opts: DrawingOptions) => {
- this._drawing = [];
- const xf = this.screenToFreeformContentsXf;
- strokeData.forEach((stroke: [InkData, string, string]) => {
- const bounds = InkField.getBounds(stroke[0]);
- 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],
- { 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().activeHideTextLabels)}, // prettier-ignore
- inkWidth,
- opts.autoColor ? stroke[1] : ActiveInkColor(),
- ActiveInkBezierApprox(),
- stroke[2] === 'none' ? ActiveInkFillColor() : stroke[2],
- ActiveInkArrowStart(),
- ActiveInkArrowEnd(),
- ActiveInkDash(),
- ActiveIsInkMask()
- );
- this._drawing.push(inkDoc);
- });
- return MarqueeView.getCollection(this._drawing, undefined, true, { left: opts.x, top: opts.y, width: 1, height: 1 });
- };
/**
* Part of regenerating a drawing--deletes the old drawing.
@@ -2007,7 +1974,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
optionItems.push({
description: 'Regenerate AI Drawing',
event: action(() => {
- SmartDrawHandler.Instance.CreateDrawingDoc = this.createDrawingDoc;
SmartDrawHandler.Instance.AddDrawing = this.addDrawing;
SmartDrawHandler.Instance.RemoveDrawing = this.removeDrawing;
!SmartDrawHandler.Instance.ShowRegenerate ? SmartDrawHandler.Instance.displayRegenerate(this._downX, this._downY - 10) : SmartDrawHandler.Instance.hideRegenerate();
diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx
index f7070c780..28371594e 100644
--- a/src/client/views/pdf/AnchorMenu.tsx
+++ b/src/client/views/pdf/AnchorMenu.tsx
@@ -139,7 +139,7 @@ export class AnchorMenu extends AntimodeMenu<AntimodeMenuProps> {
createDrawingAnnotation = action((drawing: Doc, opts: DrawingOptions, gptRes: string) => {
this.AddDrawingAnnotation(drawing);
const docData = drawing[DocData];
- docData.title = opts.text.match(/^(.*?)~~~.*$/)?.[1] || opts.text;
+ docData.title = opts.text?.match(/^(.*?)~~~.*$/)?.[1] || opts.text;
docData.ai_drawing_input = opts.text;
docData.ai_drawing_complexity = opts.complexity;
docData.ai_drawing_colored = opts.autoColor;
diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx
index fbf471900..ca308015d 100644
--- a/src/client/views/smartdraw/SmartDrawHandler.tsx
+++ b/src/client/views/smartdraw/SmartDrawHandler.tsx
@@ -27,16 +27,19 @@ import { ActiveInkArrowEnd, ActiveInkArrowStart, ActiveInkBezierApprox, ActiveIn
import { FireflyDimensionsMap, FireflyImageData, FireflyImageDimensions } from './FireflyConstants';
import './SmartDrawHandler.scss';
import { Upload } from '../../../server/SharedMediaTypes';
+import { PointData } from '../../../pen-gestures/GestureTypes';
export interface DrawingOptions {
- text: string;
- complexity: number;
- size: number;
- autoColor: boolean;
- x: number;
- y: number;
+ text?: string;
+ complexity?: number;
+ size?: number;
+ autoColor?: boolean;
+ x?: number;
+ y?: number;
}
+type svgparsedData = [PointData[], string, string];
+
/**
* The SmartDrawHandler allows users to generate drawings with GPT from text input. Users are able to enter
* the item to draw, how complex they want the drawing to be, how large the drawing should be, and whether
@@ -102,7 +105,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
* classes to customize the way the drawing docs get created. For example, the freeform canvas has a different way of
* defining document bounds, so CreateDrawingDoc is redefined when that class calls gpt draw functions.
*/
- public CreateDrawingDoc: (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => Doc | undefined = (strokeList: [InkData, string, string][], opts: DrawingOptions) => {
+ public static CreateDrawingDoc: (strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => Doc | undefined = (strokeList: [InkData, string, string][], opts: DrawingOptions) => {
const drawing: Doc[] = [];
strokeList.forEach((stroke: [InkData, string, string]) => {
const bounds = InkField.getBounds(stroke[0]);
@@ -114,7 +117,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
y: bounds.top - inkWidth / 2,
_width: bounds.width + inkWidth,
_height: bounds.height + inkWidth,
- stroke_showLabel: !BoolCast(Doc.UserDoc().activeHideTextLabels)}, // prettier-ignore
+ stroke_showLabel: false}, // prettier-ignore
inkWidth,
opts.autoColor ? stroke[1] : ActiveInkColor(),
ActiveInkBezierApprox(),
@@ -188,9 +191,9 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
/**
* This allows users to press the return/enter key to send input.
*/
- handleKeyPress = (event: React.KeyboardEvent) => {
- if (event.key === 'Enter') {
- this.handleSendClick();
+ handleKeyPress = (e: React.KeyboardEvent) => {
+ if (e.key === 'Enter') {
+ this.handleSendClick(this._pageX, this._pageY);
}
};
@@ -200,7 +203,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
* what the user sees.
*/
@action
- handleSendClick = async () => {
+ handleSendClick = async (X: number, Y: number) => {
if ((!this.ShowRegenerate && this._userInput == '') || (!this._generateImage && !this._generateDrawing)) return;
this._isLoading = true;
this._canInteract = false;
@@ -213,7 +216,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
await this.createImageWithFirefly(this._userInput);
}
if (this._generateDrawing) {
- await this.drawWithGPT({ X: this._pageX, Y: this._pageY }, this._userInput, this._complexity, this._size, this._autoColor);
+ await this.drawWithGPT({ X, Y }, this._userInput, this._complexity, this._size, this._autoColor);
}
this.hideSmartDrawHandler();
} catch (err) {
@@ -229,14 +232,14 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
/**
* Calls GPT API to create a drawing based on user input.
*/
- drawWithGPT = async (startPt: { X: number; Y: number }, input: string, complexity: number, size: number, autoColor: boolean) => {
+ drawWithGPT = async (screenPt: { X: number; Y: number }, input: string, complexity: number, size: number, autoColor: boolean) => {
if (input) {
- this._lastInput = { text: input, complexity: complexity, size: size, autoColor: autoColor, x: startPt.X, y: startPt.Y };
+ this._lastInput = { text: input, complexity: complexity, size: size, autoColor: autoColor, x: screenPt.X, y: screenPt.Y };
const res = await gptAPICall(`"${input}", "${complexity}", "${size}"`, GPTCallType.DRAW, undefined, true);
if (res) {
- const strokeData = await this.parseSvg(res, startPt, false, autoColor);
- const drawingDoc = strokeData && this.CreateDrawingDoc(strokeData.data, strokeData.lastInput, strokeData.lastRes);
- drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, res);
+ const strokeData = await this.parseSvg(res, { X: 0, Y: 0 }, false, autoColor);
+ const drawingDoc = strokeData && SmartDrawHandler.CreateDrawingDoc(strokeData.data, strokeData.lastInput, strokeData.lastRes);
+ drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, res, screenPt.X, screenPt.Y);
drawingDoc && this._selectedDocs.push(drawingDoc);
return strokeData;
} else {
@@ -334,9 +337,9 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
return gptAPICall(`"${this._lastInput.text}", "${this._lastInput.complexity}", "${this._lastInput.size}"`, GPTCallType.DRAW, undefined, true);
})();
if (res) {
- const strokeData = await this.parseSvg(res, { X: this._lastInput.x, Y: this._lastInput.y }, true, lastInput?.autoColor || this._autoColor);
+ const strokeData = await this.parseSvg(res, { X: this._lastInput.x ?? 0, Y: this._lastInput.y ?? 0 }, true, lastInput?.autoColor || this._autoColor);
this.RemoveDrawing !== unimplementedFunction && this.RemoveDrawing(true, doc);
- const drawingDoc = strokeData && this.CreateDrawingDoc(strokeData.data, strokeData.lastInput, strokeData.lastRes);
+ const drawingDoc = strokeData && SmartDrawHandler.CreateDrawingDoc(strokeData.data, strokeData.lastInput, strokeData.lastRes);
drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, res);
} else {
console.error('GPT call failed');
@@ -356,20 +359,35 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
*/
parseSvg = async (res: string, startPoint: { X: number; Y: number }, regenerate: boolean, autoColor: boolean) => {
const svg = res.match(/<svg[^>]*>([\s\S]*?)<\/svg>/g);
+
if (svg) {
this._lastResponse = svg[0];
const svgObject = await parse(svg[0]);
+ console.log(res, svgObject);
const svgStrokes: INode[] = svgObject.children;
const strokeData: [InkData, string, string][] = [];
+
+ const tl = { X: Number.MAX_SAFE_INTEGER, Y: Number.MAX_SAFE_INTEGER };
+ let last: PointData = { X: 0, Y: 0 };
svgStrokes.forEach(child => {
- const convertedBezier: InkData = SVGToBezier(child.name as SVGType, child.attributes);
+ const convertedBezier: InkData = SVGToBezier(child.name as SVGType, child.attributes, last);
+ last = convertedBezier.lastElement();
strokeData.push([
- convertedBezier.map(point => ({ X: startPoint.X + (point.X - startPoint.X) * this._scale, Y: startPoint.Y + (point.Y - startPoint.Y) * this._scale })),
+ convertedBezier.map(point => {
+ if (point.X < tl.X) tl.X = point.X;
+ if (point.Y < tl.Y) tl.Y = point.Y;
+ return { X: point.X, Y: point.Y };
+ }),
(regenerate ? this._lastInput.autoColor : autoColor) ? child.attributes.stroke : '',
(regenerate ? this._lastInput.autoColor : autoColor) ? child.attributes.fill : '',
]);
});
- return { data: strokeData, lastInput: this._lastInput, lastRes: svg[0] };
+ const mapStroke = (pd: PointData): PointData => ({ X: startPoint.X + (pd.X - tl.X) * this._scale, Y: startPoint.Y + (pd.Y - tl.Y) * this._scale });
+ return {
+ data: strokeData.map(sdata => [sdata[0].map(mapStroke), sdata[1], sdata[2]] as svgparsedData),
+ lastInput: this._lastInput,
+ lastRes: svg[0],
+ };
}
};
@@ -439,7 +457,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
},
}}
checked={this._generateImage}
- onChange={() => this._canInteract && (this._generateImage = !this._generateImage)}
+ onChange={action(() => this._canInteract && (this._generateImage = !this._generateImage))}
/>
</div>
</div>
@@ -566,7 +584,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
icon={this._isLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <AiOutlineSend />}
iconPlacement="right"
color={SettingsManager.userColor}
- onClick={this.handleSendClick}
+ onClick={() => this.handleSendClick(this._pageX, this._pageY)}
/>
</div>
{this._showOptions && (
@@ -598,7 +616,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
icon={this._isLoading && this._regenInput !== '' ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <AiOutlineSend />}
iconPlacement="right"
color={SettingsManager.userColor}
- onClick={this.handleSendClick}
+ onClick={() => this.handleSendClick(this._pageX, this._pageY)}
/>
</div>
);
@@ -644,7 +662,7 @@ export class SmartDrawHandler extends ObservableReactComponent<object> {
tooltip="Regenerate"
icon={this._isLoading && this._regenInput === '' ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width={16} height={20} /> : <FontAwesomeIcon icon={'rotate'} />}
color={SettingsManager.userColor}
- onClick={this.handleSendClick}
+ onClick={() => this.handleSendClick(this._pageX, this._pageY)}
/>
<IconButton tooltip="Edit with GPT" icon={<FontAwesomeIcon icon="pen-to-square" />} color={SettingsManager.userColor} onClick={action(() => (this._showEditBox = !this._showEditBox))} />
{this._showEditBox ? this.renderRegenerateEditBox() : null}