aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2025-02-28 14:52:39 -0500
committerbobzel <zzzman@gmail.com>2025-02-28 14:52:39 -0500
commit532f0fa22281fef1e35e3d0a6064ee57e4673253 (patch)
treef9c8c9db02bdc5de70467226681784482d1e978d /src
parent2838b8d98ab88df974fd52ba96cf5046d99298cb (diff)
added drop target for regenerating images
Diffstat (limited to 'src')
-rw-r--r--src/client/util/DragManager.ts3
-rw-r--r--src/client/views/nodes/ImageBox.scss8
-rw-r--r--src/client/views/nodes/ImageBox.tsx90
-rw-r--r--src/client/views/smartdraw/DrawingFillHandler.tsx23
4 files changed, 83 insertions, 41 deletions
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 81ea840f1..6c8179c82 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -555,9 +555,12 @@ export namespace DragManager {
let scrollAwaiter: Opt<NodeJS.Timeout>;
let startWindowDragTimer: NodeJS.Timeout | undefined;
+ let startCanEmbed = SnappingManager.CanEmbed;
const moveHandler = (e: PointerEvent) => {
e.preventDefault(); // required or dragging text menu link item ends up dragging the link button as native drag/drop
if (docDragData) {
+ if (e.ctrlKey) SnappingManager.SetCanEmbed(true);
+ else if (!startCanEmbed) SnappingManager.SetCanEmbed(false);
docDragData.userDropAction = e.ctrlKey && e.altKey ? dropActionType.copy : e.shiftKey ? dropActionType.move : e.ctrlKey ? dropActionType.embed : docDragData.defaultDropAction;
const targClassName = e.target instanceof HTMLElement && typeof e.target.className === 'string' ? e.target.className : '';
if (['lm_tab', 'lm_title_wrap', 'lm_tabs', 'lm_header'].includes(targClassName) && docDragData.draggedDocuments.length === 1) {
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 59e093683..671621bbe 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -122,6 +122,7 @@
}
}
}
+.imageBox-regenerateDropTarget,
.imageBox-alternateDropTarget {
position: absolute;
color: white;
@@ -136,6 +137,13 @@
height: 100%;
}
}
+.imageBox-regenerateDropTarget {
+ right: 30;
+ border-radius: 50%;
+ svg {
+ border-radius: 50%;
+ }
+}
.imageBox-fader img {
position: absolute;
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 55474cb7e..d122ca5b0 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -36,7 +36,7 @@ import { OverlayView } from '../OverlayView';
import { AnchorMenu } from '../pdf/AnchorMenu';
import { PinDocView, PinProps } from '../PinFuncs';
import { DrawingFillHandler } from '../smartdraw/DrawingFillHandler';
-import { FireflyImageData, isFireflyImageData } from '../smartdraw/FireflyConstants';
+import { FireflyImageData, FireflyImageDimensions, isFireflyImageData } from '../smartdraw/FireflyConstants';
import { SmartDrawHandler } from '../smartdraw/SmartDrawHandler';
import { StickerPalette } from '../smartdraw/StickerPalette';
import { StyleProp } from '../StyleProp';
@@ -45,6 +45,7 @@ import { FieldView, FieldViewProps } from './FieldView';
import { FocusViewOptions } from './FocusViewOptions';
import './ImageBox.scss';
import { OpenWhere } from './OpenWhere';
+import { RichTextField } from '../../../fields/RichTextField';
export class ImageEditorData {
// eslint-disable-next-line no-use-before-define
@@ -83,6 +84,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
private _disposers: { [name: string]: IReactionDisposer } = {};
private _getAnchor: (savedAnnotations: Opt<ObservableMap<number, HTMLDivElement[]>>, addAsAnnotation: boolean) => Opt<Doc> = () => undefined;
private _overlayIconRef = React.createRef<HTMLDivElement>();
+ private _regenerateIconRef = React.createRef<HTMLDivElement>();
private _mainCont: HTMLDivElement | null = null;
private _annotationLayer: React.RefObject<HTMLDivElement> = React.createRef();
imageRef: HTMLImageElement | null = null; // <video> ref
@@ -196,36 +198,47 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this._searchInput = selection;
};
- drop = undoable((e: Event, de: DragManager.DropEvent) => {
- if (de.complete.docDragData) {
- let added: boolean | undefined;
- const targetIsBullseye = (ele: HTMLElement): boolean => {
- if (!ele) return false;
- if (ele === this._overlayIconRef.current) return true;
- return targetIsBullseye(ele.parentElement as HTMLElement);
- };
- if (de.metaKey || targetIsBullseye(e.target as HTMLElement)) {
- added = de.complete.docDragData.droppedDocuments.reduce((last: boolean, drop: Doc) => {
- this.layoutDoc[this.fieldKey + '_usePath'] = 'alternate:hover';
- return last && Doc.AddDocToList(this.dataDoc, this.fieldKey + '_alternates', drop);
- }, true);
- } else if (de.altKey || !this.dataDoc[this.fieldKey]) {
- const layoutDoc = de.complete.docDragData?.draggedDocuments[0];
- const targetField = Doc.LayoutFieldKey(layoutDoc);
- const targetDoc = layoutDoc[DocData];
- if (targetDoc[targetField] instanceof ImageField) {
- added = true;
- this.dataDoc[this.fieldKey] = ObjectField.MakeCopy(targetDoc[targetField] as ImageField);
- Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(targetDoc), this.fieldKey);
- Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(targetDoc), this.fieldKey);
+ drop = undoable(
+ action((e: Event, de: DragManager.DropEvent) => {
+ if (de.complete.docDragData) {
+ let added: boolean | undefined;
+ const hitDropTarget = (ele: HTMLElement, dropTarget: HTMLDivElement | null): boolean => {
+ if (!ele) return false;
+ if (ele === dropTarget) return true;
+ return hitDropTarget(ele.parentElement as HTMLElement, dropTarget);
+ };
+ if (de.metaKey || hitDropTarget(e.target as HTMLElement, this._overlayIconRef.current)) {
+ added = de.complete.docDragData.droppedDocuments.reduce((last: boolean, drop: Doc) => {
+ this.layoutDoc[this.fieldKey + '_usePath'] = 'alternate:hover';
+ return last && Doc.AddDocToList(this.dataDoc, this.fieldKey + '_alternates', drop);
+ }, true);
+ } else if (hitDropTarget(e.target as HTMLElement, this._regenerateIconRef.current)) {
+ this._regenerateLoading = true;
+ const drag = de.complete.docDragData.draggedDocuments.lastElement();
+ const dragField = drag[Doc.LayoutFieldKey(drag)];
+ const oldPrompt = StrCast(this.Document.ai_firefly_prompt, StrCast(this.Document.title));
+ const newPrompt = (text: string) => (oldPrompt ? `${oldPrompt} ~~~ ${text}` : text);
+ DrawingFillHandler.drawingToImage(this.Document, 100, newPrompt(dragField instanceof RichTextField ? dragField.Text : ''), drag)?.then(action(() => (this._regenerateLoading = false)));
+ added = false;
+ } else if (de.altKey || !this.dataDoc[this.fieldKey]) {
+ const layoutDoc = de.complete.docDragData?.draggedDocuments[0];
+ const targetField = Doc.LayoutFieldKey(layoutDoc);
+ const targetDoc = layoutDoc[DocData];
+ if (targetDoc[targetField] instanceof ImageField) {
+ added = true;
+ this.dataDoc[this.fieldKey] = ObjectField.MakeCopy(targetDoc[targetField] as ImageField);
+ Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(targetDoc), this.fieldKey);
+ Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(targetDoc), this.fieldKey);
+ }
}
+ added === false && e.preventDefault();
+ added !== undefined && e.stopPropagation();
+ return added;
}
- added === false && e.preventDefault();
- added !== undefined && e.stopPropagation();
- return added;
- }
- return false;
- }, 'image drop');
+ return false;
+ }),
+ 'image drop'
+ );
@undoBatch
resolution = () => {
@@ -485,6 +498,24 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
</Tooltip>
);
}
+ @computed get regenerateImageIcon() {
+ return (
+ <div
+ className="imageBox-regenerateDropTarget"
+ ref={this._regenerateIconRef}
+ onClick={() => DocumentView.showDocument(DocCast(this.Document.ai_firefly_generatedDocs), { openLocation: OpenWhere.addRight })}
+ style={{
+ display: (this._props.isContentActive() && (SnappingManager.CanEmbed || this.Document.ai_firefly_generatedDocs)) || this._regenerateLoading ? 'block' : 'none',
+ transform: `scale(${this.uiBtnScaling})`,
+ width: this._sideBtnWidth,
+ height: this._sideBtnWidth,
+ background: 'transparent',
+ // color: SettingsManager.userBackgroundColor,
+ }}>
+ {this._regenerateLoading ? <ReactLoading type="spin" color={SettingsManager.userVariantColor} width="100%" height="100%" /> : <FontAwesomeIcon icon="portrait" color={SettingsManager.userColor} size="lg" />}
+ </div>
+ );
+ }
@computed get paths() {
const field = this.dataDoc[this.fieldKey] instanceof ImageField ? Cast(this.dataDoc[this.fieldKey], ImageField, null) : new ImageField(String(this.dataDoc[this.fieldKey])); // retrieve the primary image URL that is being rendered from the data doc
@@ -807,6 +838,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
<ReactLoading type="spin" height={50} width={50} color={'blue'} />
</div>
) : null}
+ {this.regenerateImageIcon}
{this.overlayImageIcon}
{this.annotationLayer}
{!this._mainCont || !this.DocumentView || !this._annotationLayer.current ? null : (
diff --git a/src/client/views/smartdraw/DrawingFillHandler.tsx b/src/client/views/smartdraw/DrawingFillHandler.tsx
index 7447f8afb..0a30b14b8 100644
--- a/src/client/views/smartdraw/DrawingFillHandler.tsx
+++ b/src/client/views/smartdraw/DrawingFillHandler.tsx
@@ -28,19 +28,15 @@ export class DrawingFillHandler {
const hrefParts = ImageCast(styleImg).url.href.split('.');
return `${hrefParts.slice(0, -1).join('.')}_o.${hrefParts.lastElement()}`;
});
- DocumentView.GetDocImage(drawing)?.then(imageField => {
+ return DocumentView.GetDocImage(drawing)?.then(imageField => {
if (imageField) {
const aspectRatio = (drawing.width as number) / (drawing.height as number);
- let dims: { width: number; height: number };
- if (aspectRatio > AspectRatioLimits[FireflyImageDimensions.Widescreen]) {
- dims = FireflyDimensionsMap[FireflyImageDimensions.Widescreen];
- } else if (aspectRatio > AspectRatioLimits[FireflyImageDimensions.Landscape]) {
- dims = FireflyDimensionsMap[FireflyImageDimensions.Landscape];
- } else if (aspectRatio < AspectRatioLimits[FireflyImageDimensions.Portrait]) {
- dims = FireflyDimensionsMap[FireflyImageDimensions.Portrait];
- } else {
- dims = FireflyDimensionsMap[FireflyImageDimensions.Square];
- }
+ const dims = (() => {
+ if (aspectRatio > AspectRatioLimits[FireflyImageDimensions.Widescreen]) return FireflyDimensionsMap[FireflyImageDimensions.Widescreen];
+ if (aspectRatio > AspectRatioLimits[FireflyImageDimensions.Landscape]) return FireflyDimensionsMap[FireflyImageDimensions.Landscape];
+ if (aspectRatio < AspectRatioLimits[FireflyImageDimensions.Portrait]) return FireflyDimensionsMap[FireflyImageDimensions.Portrait];
+ return FireflyDimensionsMap[FireflyImageDimensions.Square];
+ })();
const { href } = ImageCast(imageField).url;
const hrefParts = href.split('.');
const structureUrl = `${hrefParts.slice(0, -1).join('.')}_o.${hrefParts.lastElement()}`;
@@ -62,7 +58,10 @@ export class DrawingFillHandler {
_width: 500,
data_nativeWidth: info.nativeWidth,
data_nativeHeight: info.nativeHeight,
- })
+ }),
+ undefined,
+ undefined,
+ true
)
);
if (!DocumentView.getFirstDocumentView(genratedDocs)) DocumentViewInternal.addDocTabFunc(genratedDocs, OpenWhere.addRight);