aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/nodes')
-rw-r--r--src/client/views/nodes/FontIconBox/FontIconBox.tsx28
-rw-r--r--src/client/views/nodes/ImageBox.tsx6
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx76
-rw-r--r--src/client/views/nodes/generativeFill/GenerativeFill.tsx115
-rw-r--r--src/client/views/nodes/generativeFill/GenerativeFillButtons.tsx6
5 files changed, 145 insertions, 86 deletions
diff --git a/src/client/views/nodes/FontIconBox/FontIconBox.tsx b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
index 91eac675f..90ec212fc 100644
--- a/src/client/views/nodes/FontIconBox/FontIconBox.tsx
+++ b/src/client/views/nodes/FontIconBox/FontIconBox.tsx
@@ -29,6 +29,7 @@ export enum ButtonType {
DropdownList = 'dropdownList',
DropdownButton = 'dropdownBtn',
ClickButton = 'clickBtn',
+ IconClickButton = 'iconClickBtn',
ToggleButton = 'toggleBtn',
ColorButton = 'colorBtn',
ToolButton = 'toolBtn',
@@ -346,6 +347,32 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
);
}
+ @computed get iconClickButton() {
+ // Determine the type of toggle button
+ const buttonText: string = StrCast(this.rootDoc.buttonText);
+ const tooltip: string = StrCast(this.rootDoc.toolTip);
+
+ const script = ScriptCast(this.rootDoc.onClick);
+ const toggleStatus = script ? script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: undefined, _readOnly_: true }).result : false;
+ // Colors
+ const color = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Color);
+ const backgroundColor = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
+
+ return (
+ <Toggle
+ tooltip={`${tooltip}`}
+ toggleType={ToggleType.BUTTON}
+ type={Type.PRIM}
+ toggleStatus={toggleStatus}
+ text={buttonText}
+ color={color}
+ icon={this.Icon(color)!}
+ label={this.label}
+ onPointerDown={() => script.script.run({ this: this.layoutDoc, self: this.rootDoc, value: !toggleStatus, _readOnly_: false })}
+ />
+ );
+ }
+
/**
* Default
*/
@@ -393,6 +420,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
case ButtonType.DropdownButton: return this.dropdownButton;
case ButtonType.MultiToggleButton: return this.multiToggleButton;
case ButtonType.ToggleButton: return this.toggleButton;
+ case ButtonType.IconClickButton: return this.iconClickButton;
case ButtonType.ClickButton:
case ButtonType.ToolButton: return <IconButton {...btnProps} size={Size.LARGE} color={color} />;
case ButtonType.TextButton: return <Button {...btnProps} text={StrCast(this.rootDoc.buttonText)}/>;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 4ce359f3f..352e0fbdc 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -252,8 +252,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
funcs.push({
description: 'Open Image Editor',
event: action(() => {
- MainView.Instance.setImageEditorOpen(true);
- MainView.Instance.setImageEditorSource(this.choosePath(field.url));
+ MainView.Instance.imageEditorOpen = true;
+ MainView.Instance.imageEditorSource = this.choosePath(field.url);
MainView.Instance.addDoc = this.props.addDocument;
MainView.Instance.imageRootDoc = this.rootDoc;
}),
@@ -306,7 +306,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProp
choosePath(url: URL) {
const lower = url.href.toLowerCase();
if (url.protocol === 'data') return url.href;
- if (url.href.indexOf(window.location.origin) === -1 && url.href.indexOf("dashblobstore") === -1) return Utils.CorsProxy(url.href);
+ if (url.href.indexOf(window.location.origin) === -1 && url.href.indexOf('dashblobstore') === -1) return Utils.CorsProxy(url.href);
if (!/\.(png|jpg|jpeg|gif|webp)$/.test(lower)) return `/assets/unknown-file-icon-hi.png`;
const ext = extname(url.href);
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 332f0f467..5acc45d02 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -946,44 +946,46 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
console.log('Generate image from text: ', (this.dataDoc.text as RichTextField)?.Text);
GPTPopup.Instance?.setTextAnchor(this.getAnchor(false));
GPTPopup.Instance?.setImgTargetDoc(this.rootDoc);
- GPTPopup.Instance.setImgUrls([]);
- GPTPopup.Instance.setMode(GPTPopupMode.IMAGE);
- GPTPopup.Instance.setVisible(true);
+ // GPTPopup.Instance.setImgUrls([]);
+ // GPTPopup.Instance.setMode(GPTPopupMode.IMAGE);
+ // GPTPopup.Instance.setVisible(true);
GPTPopup.Instance.addToCollection = this.props.addDocument;
- GPTPopup.Instance.setLoading(true);
-
- try {
- // make this support multiple images
- let image_urls = await gptImageCall((this.dataDoc.text as RichTextField)?.Text);
- console.log(image_urls);
- if (image_urls) {
- const [result] = await Networking.PostToServer('/uploadRemoteImage', { sources: [image_urls[0]] });
- const source = Utils.prepend(result.accessPaths.agnostic.client);
- GPTPopup.Instance.setImgUrls([source]);
-
- // const newDoc = Docs.Create.ImageDocument(source, {
- // x: NumCast(this.rootDoc.x) + NumCast(this.layoutDoc._width) + 10,
- // y: NumCast(this.rootDoc.y),
- // _height: 200,
- // _width: 200,
- // data_nativeWidth: result.nativeWidth,
- // data_nativeHeight: result.nativeHeight,
- // });
- // if (Doc.IsInMyOverlay(this.rootDoc)) {
- // newDoc.overlayX = this.rootDoc.x;
- // newDoc.overlayY = NumCast(this.rootDoc.y) + NumCast(this.rootDoc._height);
- // Doc.AddToMyOverlay(newDoc);
- // } else {
- // this.props.addDocument?.(newDoc);
- // }
- // // Create link between prompt and image
- // DocUtils.MakeLink(this.rootDoc, newDoc, { link_relationship: 'Image Prompt' });
- }
- } catch (err) {
- console.log(err);
- return '';
- }
- GPTPopup.Instance.setLoading(false);
+ // GPTPopup.Instance.setLoading(true);
+ GPTPopup.Instance.setImgDesc((this.dataDoc.text as RichTextField)?.Text);
+ GPTPopup.Instance.generateImage();
+
+ // try {
+ // // make this support multiple images
+ // let image_urls = await gptImageCall((this.dataDoc.text as RichTextField)?.Text);
+ // console.log(image_urls);
+ // if (image_urls) {
+ // const [result] = await Networking.PostToServer('/uploadRemoteImage', { sources: [image_urls[0]] });
+ // const source = Utils.prepend(result.accessPaths.agnostic.client);
+ // GPTPopup.Instance.setImgUrls([source]);
+
+ // // const newDoc = Docs.Create.ImageDocument(source, {
+ // // x: NumCast(this.rootDoc.x) + NumCast(this.layoutDoc._width) + 10,
+ // // y: NumCast(this.rootDoc.y),
+ // // _height: 200,
+ // // _width: 200,
+ // // data_nativeWidth: result.nativeWidth,
+ // // data_nativeHeight: result.nativeHeight,
+ // // });
+ // // if (Doc.IsInMyOverlay(this.rootDoc)) {
+ // // newDoc.overlayX = this.rootDoc.x;
+ // // newDoc.overlayY = NumCast(this.rootDoc.y) + NumCast(this.rootDoc._height);
+ // // Doc.AddToMyOverlay(newDoc);
+ // // } else {
+ // // this.props.addDocument?.(newDoc);
+ // // }
+ // // // Create link between prompt and image
+ // // DocUtils.MakeLink(this.rootDoc, newDoc, { link_relationship: 'Image Prompt' });
+ // }
+ // } catch (err) {
+ // console.log(err);
+ // return '';
+ // }
+ // GPTPopup.Instance.setLoading(false);
};
breakupDictation = () => {
diff --git a/src/client/views/nodes/generativeFill/GenerativeFill.tsx b/src/client/views/nodes/generativeFill/GenerativeFill.tsx
index f8f9fe077..99068d647 100644
--- a/src/client/views/nodes/generativeFill/GenerativeFill.tsx
+++ b/src/client/views/nodes/generativeFill/GenerativeFill.tsx
@@ -3,7 +3,7 @@ import React = require('react');
import { useEffect, useRef, useState } from 'react';
import { APISuccess, ImageUtility } from './generativeFillUtils/ImageHandler';
import { BrushHandler } from './generativeFillUtils/BrushHandler';
-import { Box, IconButton, Slider, TextField } from '@mui/material';
+import { Box, Checkbox, FormControlLabel, IconButton, Slider, TextField } from '@mui/material';
import { CursorData, Point } from './generativeFillUtils/generativeFillInterfaces';
import { activeColor, canvasSize, eraserColor, freeformRenderSize, newCollectionSize, offsetDistanceY, offsetX } from './generativeFillUtils/generativeFillConstants';
import { PointerHandler } from './generativeFillUtils/PointerHandler';
@@ -19,6 +19,7 @@ import { Cast, DocCast, NumCast } from '../../../../fields/Types';
import { CollectionDockingView } from '../../collections/CollectionDockingView';
import { OpenWhere, OpenWhereMod } from '../DocumentView';
import { Oval } from 'react-loader-spinner';
+import { CheckBox } from '../../search/CheckBox';
/**
* For images not 1024x1024 fill in the rest in solid black, or a
@@ -72,6 +73,7 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
const [input, setInput] = useState('');
const [loading, setLoading] = useState(false);
const [saveLoading, setSaveLoading] = useState(false);
+ const [isNewCollection, setIsNewCollection] = useState(false);
// the current image in the main canvas
const currImg = useRef<HTMLImageElement | null>(null);
// the unedited version of each generation (parent)
@@ -81,9 +83,6 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
// stores redo stack
const redoStack = useRef<string[]>([]);
- // early stage properly, likely will get rid of
- const freeformPosition = useRef<number[]>([0, 0]);
-
// which urls were already saved to canvas
const savedSrcs = useRef<Set<string>>(new Set());
@@ -91,7 +90,6 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
const newCollectionRef = useRef<Doc | null>(null);
const parentDoc = useRef<Doc | null>(null);
const childrenDocs = useRef<Doc[]>([]);
- const addToExistingCollection = useRef<boolean>(false);
// Undo and Redo
const handleUndo = () => {
@@ -111,10 +109,13 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
};
const handleRedo = () => {
- // TODO: handle undo as well
+ const ctx = ImageUtility.getCanvasContext(canvasRef);
+ if (!ctx || !currImg.current || !canvasRef.current) return;
+
const target = redoStack.current[redoStack.current.length - 1];
if (!target) {
} else {
+ undoStack.current = [...undoStack.current, canvasRef.current?.toDataURL()];
const img = new Image();
img.src = target;
ImageUtility.drawImgToCanvas(img, canvasRef);
@@ -188,7 +189,6 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
ImageUtility.drawImgToCanvas(img, canvasRef);
currImg.current = img;
originalImg.current = img;
- freeformPosition.current = [0, 0];
return () => {
console.log('cleanup');
@@ -197,7 +197,6 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
childrenDocs.current = [];
currImg.current = null;
originalImg.current = null;
- freeformPosition.current = [0, 0];
undoStack.current = [];
redoStack.current = [];
};
@@ -266,24 +265,25 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
// create first image
if (!newCollectionRef.current) {
- if (addToExistingCollection.current) {
+ if (!isNewCollection) {
+ // newcollection should stay null
+ } else {
+ if (!(originalImg.current && imageRootDoc)) return;
+ // create new collection and add it to the view
+ newCollectionRef.current = Docs.Create.FreeformDocument([], {
+ x: NumCast(imageRootDoc.x) + NumCast(imageRootDoc._width) + offsetX,
+ y: NumCast(imageRootDoc.y),
+ _width: newCollectionSize,
+ _height: newCollectionSize,
+ title: 'Image edit collection',
+ });
+ DocUtils.MakeLink(imageRootDoc, newCollectionRef.current, { link_relationship: 'Image Edit Version History', link_displayLine: false });
+ // add the doc to the main freeform
+ addDoc?.(newCollectionRef.current);
+ await createNewImgDoc(originalImg.current, true);
}
- if (!(originalImg.current && imageRootDoc)) return;
- console.log('creating first image');
- // create new collection and add it to the view
- newCollectionRef.current = Docs.Create.FreeformDocument([], {
- x: NumCast(imageRootDoc.x) + NumCast(imageRootDoc._width) + offsetX,
- y: NumCast(imageRootDoc.y),
- _width: newCollectionSize,
- _height: newCollectionSize,
- title: 'Image edit collection',
- });
- DocUtils.MakeLink(imageRootDoc, newCollectionRef.current, { link_relationship: 'Image Edit Version History', link_displayLine: false });
- // add the doc to the main freeform
- // addDoc?.(newCollectionRef.current);
- await createNewImgDoc(originalImg.current, true);
} else {
- parentDoc.current = childrenDocs.current[childrenDocs.current.length - 1];
+ // parentDoc.current = childrenDocs.current[childrenDocs.current.length - 1];
childrenDocs.current = [];
}
@@ -292,12 +292,24 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
const { urls } = res as APISuccess;
const image = new Image();
image.src = urls[0];
+
+ // need to crop images agh
+ // save to dash
+
+ // const imageRes = await Promise.all(
+ // urls.map(async url => {
+ // const newImg = new Image();
+ // newImg.src = url;
+ // await onSave(newImg);
+ // })
+ // );
+
+ // map each url to [url, imgDoc]
setEdits(urls);
+
ImageUtility.drawImgToCanvas(image, canvasRef);
currImg.current = image;
- onSave();
- freeformPosition.current[0] += 1;
- freeformPosition.current[1] = 0;
+ // onSave(currImg.current);
} catch (err) {
console.log(err);
}
@@ -324,7 +336,7 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
// creates a new image document and returns its reference
const createNewImgDoc = async (img: HTMLImageElement, firstDoc: boolean): Promise<Doc | undefined> => {
- if (!newCollectionRef.current || !imageRootDoc) return;
+ if (!imageRootDoc) return;
const src = img.src;
const [result] = await Networking.PostToServer('/uploadRemoteImage', { sources: [src] });
const source = Utils.prepend(result.accessPaths.agnostic.client);
@@ -332,7 +344,6 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
if (firstDoc) {
const x = 0;
const initialY = 0;
- console.log('first doc');
const newImg = Docs.Create.ImageDocument(source, {
x: x,
@@ -343,16 +354,19 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
data_nativeHeight: result.nativeHeight,
});
- Doc.AddDocToList(newCollectionRef.current, undefined, newImg);
+ if (isNewCollection && newCollectionRef.current) {
+ Doc.AddDocToList(newCollectionRef.current, undefined, newImg);
+ } else {
+ addDoc?.(newImg);
+ }
+
parentDoc.current = newImg;
return newImg;
} else {
if (!parentDoc.current) return;
const x = NumCast(parentDoc.current.x) + freeformRenderSize + offsetX;
// dummy position
- console.log('creating child elements');
const initialY = 0;
-
const newImg = Docs.Create.ImageDocument(source, {
x: x,
y: initialY,
@@ -363,21 +377,26 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
});
childrenDocs.current.push(newImg);
+
+ if (isNewCollection && newCollectionRef.current) {
+ Doc.AddDocToList(newCollectionRef.current, undefined, newImg);
+ } else {
+ addDoc?.(newImg);
+ }
+
DocUtils.MakeLink(parentDoc.current, newImg, { link_relationship: 'Image Edit', link_displayLine: true });
adjustImgPositions();
-
- Doc.AddDocToList(newCollectionRef.current, undefined, newImg);
return newImg;
}
};
// need to maybe call on every img click, not just when the save btn is clicked
- const onSave = async () => {
+ const onSave = async (img: HTMLImageElement) => {
setSaveLoading(true);
- if (!currImg.current || !originalImg.current || !imageRootDoc) return;
+ // if (!currImg.current || !originalImg.current || !imageRootDoc) return;
try {
console.log('creating another image');
- await createNewImgDoc(currImg.current, false);
+ await createNewImgDoc(img, false);
} catch (err) {
console.log(err);
}
@@ -387,7 +406,7 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
const handleViewClose = () => {
if (newCollectionRef.current) {
newCollectionRef.current.fitContentOnce = true;
- CollectionDockingView.AddSplit(newCollectionRef.current, OpenWhereMod.right);
+ // CollectionDockingView.AddSplit(newCollectionRef.current, OpenWhereMod.right);
}
MainView.Instance.setImageEditorOpen(false);
MainView.Instance.setImageEditorSource('');
@@ -399,7 +418,20 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
<div className="generativeFillControls">
<h1>AI Image Editor</h1>
<div style={{ display: 'flex', alignItems: 'center', gap: '1.5rem' }}>
- <Buttons canvasRef={canvasRef} currImg={currImg} getEdit={getEdit} loading={loading} onSave={onSave} onReset={handleReset} />
+ <FormControlLabel
+ control={
+ <Checkbox
+ checked={isNewCollection}
+ onChange={e => {
+ setIsNewCollection(prev => !prev);
+ }}
+ />
+ }
+ label={'Create New Collection'}
+ labelPlacement="end"
+ sx={{ whiteSpace: 'nowrap' }}
+ />
+ <Buttons canvasRef={canvasRef} currImg={currImg} getEdit={getEdit} loading={loading} onReset={handleReset} />
<IconButton onClick={handleViewClose}>
<BsX color={activeColor} />
</IconButton>
@@ -491,13 +523,14 @@ const GenerativeFill = ({ imageEditorOpen, imageEditorSource, imageRootDoc, addD
height={100}
src={edit}
onClick={async () => {
- // if (savedSrcs.current.has(edit)) return;
const img = new Image();
img.src = edit;
ImageUtility.drawImgToCanvas(img, canvasRef);
currImg.current = img;
savedSrcs.current.add(edit);
- await onSave();
+ undoStack.current = [];
+ redoStack.current = [];
+ await onSave(img);
}}
/>
))}
diff --git a/src/client/views/nodes/generativeFill/GenerativeFillButtons.tsx b/src/client/views/nodes/generativeFill/GenerativeFillButtons.tsx
index 53c6cec84..b4d56b408 100644
--- a/src/client/views/nodes/generativeFill/GenerativeFillButtons.tsx
+++ b/src/client/views/nodes/generativeFill/GenerativeFillButtons.tsx
@@ -11,14 +11,10 @@ interface ButtonContainerProps {
currImg: React.MutableRefObject<HTMLImageElement | null>;
getEdit: () => Promise<void>;
loading: boolean;
- onSave: () => Promise<void>;
onReset: () => void;
}
-const Buttons = ({ canvasRef, currImg, loading, getEdit, onSave, onReset }: ButtonContainerProps) => {
- const handleSave = () => {
- onSave();
- };
+const Buttons = ({ canvasRef, currImg, loading, getEdit, onReset }: ButtonContainerProps) => {
return (
<div className="generativeFillBtnContainer">