diff options
-rw-r--r-- | src/client/views/PropertiesView.tsx | 80 | ||||
-rw-r--r-- | src/client/views/smartdraw/DrawingFillHandler.tsx | 60 | ||||
-rw-r--r-- | src/client/views/smartdraw/SmartDrawHandler.tsx | 29 |
3 files changed, 87 insertions, 82 deletions
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx index 7e8087808..4e12e0b2d 100644 --- a/src/client/views/PropertiesView.tsx +++ b/src/client/views/PropertiesView.tsx @@ -3,7 +3,6 @@ import { faAnchor, faArrowRight, faWindowMaximize } from '@fortawesome/free-soli import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Checkbox, Tooltip } from '@mui/material'; import { Colors, EditableText, IconButton, NumberInput, Size, Slider, Toggle, ToggleType, Type } from 'browndash-components'; -import { Property } from 'csstype'; import { concat } from 'lodash'; import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; @@ -45,6 +44,7 @@ import { StyleProviderFuncType } from './nodes/FieldView'; import { OpenWhere } from './nodes/OpenWhere'; import { PresBox, PresEffect, PresEffectDirection } from './nodes/trails'; import { SmartDrawHandler } from './smartdraw/SmartDrawHandler'; +import { DrawingFillHandler } from './smartdraw/DrawingFillHandler'; interface PropertiesViewProps { width: number; @@ -141,7 +141,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps } @computed get isText() { - return [DocumentType.RTF, DocumentType.EQUATION, DocumentType.LABEL].includes(this.selectedDoc?.type as DocumentType); + return this.selectedDoc?.type === DocumentType.RTF; } @computed get isInk() { return this.selectedDoc?.type === DocumentType.INK; @@ -830,8 +830,12 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps set shapeWid(value) { this.selectedDoc && (this.selectedDoc._width = Math.round(value * 100) / 100); } // prettier-ignore @computed get shapeHgt() { return NumCast(this.selectedDoc?._height); } // prettier-ignore set shapeHgt(value) { this.selectedDoc && (this.selectedDoc._height = Math.round(value * 100) / 100); } // prettier-ignore - @computed get strokeThk(){ return NumCast(this.selectedStrokes.lastElement()?.[DocData].stroke_width, 1); } // prettier-ignore - set strokeThk(value) { this.selectedStrokes.forEach(doc => { doc[DocData].stroke_width = Math.round(value * 100) / 100; }); } // prettier-ignore + @computed get strokeThk(){ return NumCast(this.selectedStrokes.lastElement()?.[DocData].stroke_width); } // prettier-ignore + set strokeThk(value) { + this.selectedStrokes.forEach(doc => { + doc[DocData].stroke_width = Math.round(value * 100) / 100; + }); + } @computed get hgtInput() { return this.inputBoxDuo( @@ -981,19 +985,35 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps return ( <div> {!targetDoc.layout_isSvg && this.containsInkDoc && ( - <div className="color"> - <Toggle - text={'Color with GPT'} - color={SettingsManager.userColor} - icon={<FontAwesomeIcon icon="fill-drip" />} - iconPlacement="left" - align="flex-start" - fillWidth - toggleType={ToggleType.BUTTON} - onClick={undoable(() => { - SmartDrawHandler.Instance.colorWithGPT(targetDoc); - }, 'colorWithGPT')} - /> + <div> + <div className="drawing-to-image"> + <Toggle + text={'Create Image'} + color={SettingsManager.userColor} + icon={<FontAwesomeIcon icon="fill-drip" />} + iconPlacement="left" + align="flex-start" + fillWidth + toggleType={ToggleType.BUTTON} + onClick={undoable(() => { + DrawingFillHandler.drawingToImage(targetDoc, 'fill in the details of this image'); + }, 'createImage')} + /> + </div> + <div className="color"> + <Toggle + text={'Color with GPT'} + color={SettingsManager.userColor} + icon={<FontAwesomeIcon icon="fill-drip" />} + iconPlacement="left" + align="flex-start" + fillWidth + toggleType={ToggleType.BUTTON} + onClick={undoable(() => { + SmartDrawHandler.Instance.colorWithGPT(targetDoc); + }, 'colorWithGPT')} + /> + </div> </div> )} <div className="smooth"> @@ -1022,13 +1042,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps doc[DocData].stroke_dash = value ? this._lastDash : undefined; }); } - @computed get lineCapStk() { return (this.getField('stroke_lineCap') || 'round' ) as Property.StrokeLinecap; } // prettier-ignore - set lineCapStk(value) { - this.selectedStrokes.forEach(doc => { - doc[DocData].stroke_lineCap = value; - }); - } - @computed get widthStk() { return this.getField('stroke') || '1'; } // prettier-ignore + @computed get widthStk() { return this.getField('stroke_width') || '1'; } // prettier-ignore set widthStk(value) { this.selectedStrokes.forEach(doc => { doc[DocData].stroke_width = Number(value); @@ -1130,6 +1144,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps <div className="arrows-head"> <div className="arrows-head-title">Arrow Head: </div> <input + key="markHead" className="arrows-head-input" type="checkbox" checked={this.markHead !== ''} @@ -1139,25 +1154,16 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps <div className="arrows-tail"> <div className="arrows-tail-title">Arrow End: </div> <input + key="markTail" className="arrows-tail-input" type="checkbox" checked={this.markTail !== ''} - onChange={undoable(action(() => { this.markTail = this.markTail ? '' : 'arrow'; }) ,"change arrow tail")} + onChange={undoable( + action(() => { this.markTail = this.markTail ? '' : 'arrow'; }) ,"change arrow tail" + )} /> </div> </div> - <div className="arrows"> - {["butt", "round", "square"].map(cap => - <div className="arrows-tail" key={cap}> - <div className="arrows-tail-title">{cap}</div> - <input - className="arrows-tail-input" - type="checkbox" - checked={this.lineCapStk === cap} - onChange={undoable(action(() => { this.lineCapStk = cap as Property.StrokeLinecap; }), `change lineCap ${cap}`)} - /> - </div>)} - </div> <div className="dashed"> <div className="dashed-title">Dashed Line:</div> <input key="markHead" className="dashed-input" type="checkbox" checked={this.dashdStk === '2'} onChange={this.changeDash} /> diff --git a/src/client/views/smartdraw/DrawingFillHandler.tsx b/src/client/views/smartdraw/DrawingFillHandler.tsx index 508ee557d..c3c762181 100644 --- a/src/client/views/smartdraw/DrawingFillHandler.tsx +++ b/src/client/views/smartdraw/DrawingFillHandler.tsx @@ -12,37 +12,39 @@ import { ImageUtility } from '../nodes/imageEditor/imageEditorUtils/ImageHandler import { OpenWhere } from '../nodes/OpenWhere'; import { ObservableReactComponent } from '../ObservableReactComponent'; -@observer -export class DrawingFillHandler extends ObservableReactComponent<object> { - static Instance: DrawingFillHandler; - - constructor(props: object) { - super(props); - makeObservable(this); - DrawingFillHandler.Instance = this; - } - - @action - drawingToImage = async (drawing: Doc, prompt: string) => { +export class DrawingFillHandler { + static drawingToImage = async (drawing: Doc, prompt: string) => { const imageField = await DocumentView.GetDocImage(drawing); if (!imageField) return; - const image = new Image(); - image.src = imageField.url?.href; - await new Promise<void>((resolve, reject) => { - image.onload = () => resolve(); - image.onerror = () => reject(new Error('Error loading image')); - }); + const { href } = ImageCast(imageField).url; + const hrefParts = href.split('.'); + const hrefComplete = `${hrefParts[0]}_o.${hrefParts[1]}`; + try { + const response = await fetch(hrefComplete); + const blob: Blob = await response.blob(); + const strength: number = 100; + const img = await Networking.PostToServer('/queryFireflyImage', { prompt, blob, strength }); + DocumentViewInternal.addDocTabFunc(Docs.Create.ImageDocument(img, {}), OpenWhere.addRight); + // Networking.PostToServer('/queryFireflyImage', { prompt, blob, strength }).then(img => DocumentViewInternal.addDocTabFunc(Docs.Create.ImageDocument(img, {}), OpenWhere.addRight)); + } catch (error) { + console.error('Error fetching image:', error); + return; + } - const canvas = document.createElement('canvas'); - canvas.width = image.width; - canvas.height = image.height; - const ctx = canvas.getContext('2d'); - if (!ctx) return; - ctx.globalCompositeOperation = 'source-over'; - ctx.clearRect(0, 0, image.width, image.height); - ctx.drawImage(image, 0, 0); - const blob: Blob = await ImageUtility.canvasToBlob(canvas); - const strength: number = 100; - Networking.PostToServer('/queryFireflyImage', { prompt, blob, strength }).then(img => DocumentViewInternal.addDocTabFunc(Docs.Create.ImageDocument(img, {}), OpenWhere.addRight)); + // const image = new Image(); + // image.src = imageField.url?.href; + // // image.onload = async () => { + // const canvas = document.createElement('canvas'); + // canvas.width = image.width; + // canvas.height = image.height; + // const ctx = canvas.getContext('2d'); + // if (!ctx) return; + // ctx.globalCompositeOperation = 'source-over'; + // ctx.clearRect(0, 0, image.width, image.height); + // ctx.drawImage(image, 0, 0); + // const blob: Blob = await ImageUtility.canvasToBlob(canvas); + // const strength: number = 100; + // Networking.PostToServer('/queryFireflyImage', { prompt, blob, strength }).then(img => DocumentViewInternal.addDocTabFunc(Docs.Create.ImageDocument(img, {}), OpenWhere.addRight)); + // }; }; } diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx index e962291f6..23ab7657f 100644 --- a/src/client/views/smartdraw/SmartDrawHandler.tsx +++ b/src/client/views/smartdraw/SmartDrawHandler.tsx @@ -13,7 +13,6 @@ import { Doc, DocListCast } from '../../../fields/Doc'; import { DocData } from '../../../fields/DocSymbols'; import { InkData, InkField, InkTool } from '../../../fields/InkField'; import { BoolCast, ImageCast, NumCast, StrCast } from '../../../fields/Types'; -import { Networking } from '../../Network'; import { GPTCallType, gptAPICall, gptDrawingColor } from '../../apis/gpt/GPT'; import { Docs } from '../../documents/Documents'; import { SettingsManager } from '../../util/SettingsManager'; @@ -22,8 +21,7 @@ import { SVGToBezier, SVGType } from '../../util/bezierFit'; import { InkingStroke } from '../InkingStroke'; import { ObservableReactComponent } from '../ObservableReactComponent'; import { MarqueeView } from '../collections/collectionFreeForm'; -import { ActiveInkArrowEnd, ActiveInkArrowStart, ActiveInkBezierApprox, ActiveInkColor, ActiveInkDash, ActiveInkFillColor, ActiveInkWidth, ActiveIsInkMask, DocumentView, DocumentViewInternal } from '../nodes/DocumentView'; -import { OpenWhere } from '../nodes/OpenWhere'; +import { ActiveInkArrowEnd, ActiveInkArrowStart, ActiveInkDash, ActiveInkFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, DocumentView } from '../nodes/DocumentView'; import './SmartDrawHandler.scss'; export interface DrawingOptions { @@ -238,21 +236,20 @@ export class SmartDrawHandler extends ObservableReactComponent<object> { * Calls GPT API to create a drawing based on user input. */ @action - drawWithGPT = (startPt: { X: number; Y: number }, prompt: string, complexity: number, size: number, autoColor: boolean) => { - if (prompt === '') return; - this._lastInput = { text: prompt, complexity: complexity, size: size, autoColor: autoColor, x: startPt.X, y: startPt.Y }; - - Networking.PostToServer('/queryFireflyImage', { prompt }).then(img => DocumentViewInternal.addDocTabFunc(Docs.Create.ImageDocument(img, { title: prompt }), OpenWhere.addRight)); - - const result = gptAPICall(`"${prompt}", "${complexity}", "${size}"`, GPTCallType.DRAW, undefined, true).then(res => - this.parseSvg(res, startPt, false, autoColor).then(strokeData => { - const drawingDoc = strokeData && this.CreateDrawingDoc(strokeData.data, strokeData.lastInput, strokeData.lastRes); - drawingDoc && this.AddDrawing(drawingDoc, this._lastInput, res); - }) - ); + 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 }; + const res = await gptAPICall(`"${input}", "${complexity}", "${size}"`, GPTCallType.DRAW, undefined, true); + if (!res) { + console.error('GPT call failed'); + return; + } + 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); this._errorOccurredOnce = false; - return result; + return strokeData; }; /** |