aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/client/views/DocumentDecorations.tsx25
-rw-r--r--src/client/views/nodes/ImageBox.scss42
-rw-r--r--src/client/views/nodes/ImageBox.tsx24
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx1
-rw-r--r--src/client/views/nodes/imageEditor/imageMeshTool/imageMeshToolButton.tsx15
5 files changed, 46 insertions, 61 deletions
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 2d39b827d..ab665e984 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -448,8 +448,8 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
DocumentView.Selected()
.filter(dv => e.shiftKey && dv.ComponentView instanceof ImageBox)
.forEach(dv => {
- dv.Document._outpaintingOriginalWidth = NumCast(dv.Document._width);
- dv.Document._outpaintingOriginalHeight = NumCast(dv.Document._height);
+ dv.Document[dv.ComponentView!.fieldKey + '_outpaintOriginalWidth'] = NumCast(dv.Document._width);
+ dv.Document[dv.ComponentView!.fieldKey + '_outpaintOriginalHeight'] = NumCast(dv.Document._height);
});
setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction);
e.stopPropagation();
@@ -502,14 +502,15 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
this._interactionLock = true;
this._snapPt = thisPt;
- const notOutpainted = DocumentView.Selected().filter(dv => !e.shiftKey || !(dv.ComponentView instanceof ImageBox));
- // Special handling for shift-drag resize (outpainting of Images)
- DocumentView.Selected()
- .filter(dv => !notOutpainted.includes(dv))
- .forEach(dv => this.resizeViewForOutpainting(dv, refPt, scale, { dragHdl, shiftKey: e.shiftKey })); // Adjust only the document dimensions without scaling internal content
+ const outpainted = e.shiftKey ? DocumentView.Selected().filter(dv => dv.ComponentView instanceof ImageBox) : [];
+ const notOutpainted = e.shiftKey ? DocumentView.Selected().filter(dv => !outpainted.includes(dv)) : DocumentView.Selected();
- // Regular resize behavior for docs not being outpainted
+ // Special handling for shift-drag resize (outpainting of Images by resizing without scaling content - fill in with firefly GAI)
+ e.shiftKey && outpainted.forEach(dv => this.resizeViewForOutpainting(dv, refPt, scale, { dragHdl, shiftKey: e.shiftKey }));
+
+ // Special handling for not outpainted Docs when ctrl-resizing (setup native dimesions for modification)
e.ctrlKey && notOutpainted.forEach(docView => !Doc.NativeHeight(docView.Document) && docView.toggleNativeDimensions());
+
const hasFixedAspect = notOutpainted.map(dv => dv.Document).some(this.hasFixedAspect);
const scaleAspect = { x: scale.x === 1 && hasFixedAspect ? scale.y : scale.x, y: scale.x !== 1 && hasFixedAspect ? scale.x : scale.y };
notOutpainted.forEach(docView => this.resizeView(docView, refPt, scaleAspect, { dragHdl, freezeNativeDims: e.ctrlKey }));
@@ -546,20 +547,14 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
const { deltaX, deltaY } = this.realignRefPt(doc, refCent, originalWidth, originalHeight);
doc.x = NumCast(doc.x) + deltaX;
doc.y = NumCast(doc.y) + deltaY;
-
doc._layout_modificationDate = new DateField();
};
@action
- onPointerUp = (e: PointerEvent): void => {
+ onPointerUp = () => {
SnappingManager.SetIsResizing(undefined);
SnappingManager.clearSnapLines();
- // Check if any outpainting needs to be processed
- DocumentView.Selected()
- .filter(dv => e.shiftKey && dv.ComponentView instanceof ImageBox)
- .forEach(view => (view.ComponentView as ImageBox).processOutpainting());
-
this._resizeHdlId = '';
this._resizeUndo?.end();
diff --git a/src/client/views/nodes/ImageBox.scss b/src/client/views/nodes/ImageBox.scss
index 9fc20ffd4..ac1a6ece9 100644
--- a/src/client/views/nodes/ImageBox.scss
+++ b/src/client/views/nodes/ImageBox.scss
@@ -106,7 +106,7 @@
height: 100%;
img {
object-fit: contain;
- height: 100%;
+ height: fit-content;
}
.imageBox-fadeBlocker,
@@ -249,27 +249,29 @@
background: white;
padding: 20px;
border-radius: 8px;
- box-shadow: 0 4px 12px rgba(0,0,0,0.2);
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
z-index: 10000;
-
- h3 { margin-top: 0; }
-
+
+ h3 {
+ margin-top: 0;
+ }
+
input {
- width: 300px;
- padding: 8px;
- margin-bottom: 10px;
+ width: 300px;
+ padding: 8px;
+ margin-bottom: 10px;
}
-
+
.buttons {
- display: flex;
- justify-content: flex-end;
- gap: 10px;
-
- .generate-btn {
- background: #0078d4;
- color: white;
- border: none;
- padding: 8px 16px;
- }
+ display: flex;
+ justify-content: flex-end;
+ gap: 10px;
+
+ .generate-btn {
+ background: #0078d4;
+ color: white;
+ border: none;
+ padding: 8px 16px;
+ }
}
- } \ No newline at end of file
+}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 0b6814c01..4fe23ba7b 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -219,6 +219,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
},
{ fireImmediately: true }
);
+ this._disposers.outpaint = reaction(
+ () => this.Document[this.fieldKey + '_outpaintOriginalWidth'] !== undefined && !SnappingManager.ShiftKey,
+ complete => complete && this.openOutpaintPrompt(),
+ { fireImmediately: true }
+ );
}
componentWillUnmount() {
@@ -421,13 +426,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
const field = Cast(this.dataDoc[this.fieldKey], ImageField);
if (!field) return;
- const origWidth = NumCast(this.Document._outpaintingOriginalWidth);
- const origHeight = NumCast(this.Document._outpaintingOriginalHeight);
-
- if (!origWidth || !origHeight) {
- console.error('Original dimensions (_outpaintingOriginalWidth/_outpaintingOriginalHeight) not set. Ensure resizeViewForOutpainting was called first.');
- return;
- }
+ const origWidth = NumCast(this.Document[this.fieldKey + '_outpaintOriginalWidth']);
+ const origHeight = NumCast(this.Document[this.fieldKey + '_outpaintOriginalHeight']);
// Set flag that outpainting is in progress
this._outpaintingInProgress = true;
@@ -493,8 +493,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this.Document.$ai = true;
this.Document.$ai_outpainted = true;
this.Document.$ai_outpaint_prompt = customPrompt;
- this.Document._outpaintingOriginalWidth = undefined;
- this.Document._outpaintingOriginalHeight = undefined;
+ this.Document[this.fieldKey + '_outpaintOriginalWidth'] = undefined;
+ this.Document[this.fieldKey + '_outpaintOriginalHeight'] = undefined;
} else {
this.Document._width = origWidth;
this.Document._height = origHeight;
@@ -514,11 +514,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
}
};
- processOutpainting = () => this.openOutpaintPrompt();
-
componentUI = () =>
!this._showOutpaintPrompt ? null : (
- <div className="imageBox-regenerate-dialog" style={{ backgroundColor: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
+ <div key="imageBox-componentui" className="imageBox-regenerate-dialog" style={{ backgroundColor: SettingsManager.userBackgroundColor, color: SettingsManager.userColor }}>
<h3>Outpaint Image</h3>
<EditableText
placeholder="Enter a prompt for extending the image:"
@@ -775,7 +773,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
ref={action((r: HTMLImageElement | null) => (this.imageRef = r))}
key="paths"
src={srcpath}
- style={{ transform, transformOrigin, height: 'fit-content' }}
+ style={{ transform, transformOrigin, height: this.Document[this.fieldKey + '_outpaintOriginalWidth'] !== undefined ? '100%' : undefined }}
onError={action(e => (this._error = e.toString()))}
draggable={false}
width={nativeWidth}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index f4cbbcc9e..1ff902ba2 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1367,7 +1367,6 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FormattedTextB
};
doPaste = (view: EditorView, data: DataTransfer | null) => {
const html = data?.getData('text/html');
- const text = data?.getData('text/plain');
const pdfAnchorId = data?.getData('dash/pdfAnchor');
if (html && !pdfAnchorId) {
const replaceDivsWithParagraphs = (expr: string) => {
diff --git a/src/client/views/nodes/imageEditor/imageMeshTool/imageMeshToolButton.tsx b/src/client/views/nodes/imageEditor/imageMeshTool/imageMeshToolButton.tsx
index c02a1eb94..e580c7070 100644
--- a/src/client/views/nodes/imageEditor/imageMeshTool/imageMeshToolButton.tsx
+++ b/src/client/views/nodes/imageEditor/imageMeshTool/imageMeshToolButton.tsx
@@ -13,20 +13,11 @@ interface ButtonContainerProps {
btnText: string;
imageWidth: number;
imageHeight: number;
- gridXSize: number; // X subdivisions
- gridYSize: number; // Y subdivisions
+ gridXSize: number; // X subdivisions
+ gridYSize: number; // Y subdivisions
}
-export function MeshTransformButton({
- loading,
- onClick,
- onReset,
- btnText,
- imageWidth,
- imageHeight,
- gridXSize,
- gridYSize
-}: ButtonContainerProps) {
+export function MeshTransformButton({ loading, onClick, onReset, btnText, imageWidth, imageHeight, gridXSize, gridYSize }: ButtonContainerProps) {
const [showGrid, setShowGrid] = React.useState(false);
const [isGridInteractive, setIsGridInteractive] = React.useState(false); // Controls the dragging of control points
const imageRef = React.useRef<HTMLImageElement>(null); // Reference to the image element