aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/nodes/ImageBox.tsx
diff options
context:
space:
mode:
authorsharkiecodes <lanyi_stroud@brown.edu>2025-06-10 11:12:23 -0400
committersharkiecodes <lanyi_stroud@brown.edu>2025-06-10 11:12:23 -0400
commit272534c8a7517d08c70928c96d487d84b14772f6 (patch)
tree0e3e9a8cc83b8ba96b2bd49c9fc726b16411d60c /src/client/views/nodes/ImageBox.tsx
parentc5981504058e0696827b4048fcd908a58fb0b0d3 (diff)
parentb91057d00512446339e48fb8488a97a1e5ef03d5 (diff)
Merge branch 'master' into lanyi-branch
Diffstat (limited to 'src/client/views/nodes/ImageBox.tsx')
-rw-r--r--src/client/views/nodes/ImageBox.tsx88
1 files changed, 54 insertions, 34 deletions
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 79a218e45..1e16bbfc9 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -113,6 +113,28 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this._props.setContentViewBox?.(this);
}
+ @computed get oupaintOriginalSize(): { width: number; height: number } {
+ return {
+ width: NumCast(this.Document[this.fieldKey + '_outpaintOriginalWidth']),
+ height: NumCast(this.Document[this.fieldKey + '_outpaintOriginalHeight']),
+ };
+ }
+ set outpaintOriginalSize(prop: { width: number; height: number } | undefined) {
+ this.Document[this.fieldKey + '_outpaintOriginalWidth'] = prop?.width;
+ this.Document[this.fieldKey + '_outpaintOriginalHeight'] = prop?.height;
+ }
+
+ @computed get imgNativeSize() {
+ return {
+ nativeWidth: NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth'], 500)),
+ nativeHeight: NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], NumCast(this.layoutDoc[this.fieldKey + '_nativeHeight'], 500)),
+ };
+ }
+ set imgNativeSize(prop: { nativeWidth: number; nativeHeight: number }) {
+ this.dataDoc[this.fieldKey + '_nativeWidth'] = prop.nativeWidth;
+ this.dataDoc[this.fieldKey + '_nativeHeight'] = prop.nativeHeight;
+ }
+
protected createDropTarget = (ele: HTMLDivElement) => {
this._mainCont = ele;
this._dropDisposer?.();
@@ -207,7 +229,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
() => ({ nativeSize: this.nativeSize, width: NumCast(this.layoutDoc._width), height: this.layoutDoc._height }),
({ nativeSize, width, height }) => {
if (!this.layoutDoc._layout_nativeDimEditable || !height || this.layoutDoc.layout_resetNativeDim) {
- this.layoutDoc.layout_resetNativeDim = undefined; // template images need to reset their dimensions when they are rendered with content. afterwards, remove this flag.
+ if (!this._props.TemplateDataDocument) this.layoutDoc._nativeWidth = this.layoutDoc._nativeHeight = undefined;
+ this.layoutDoc.layout_resetNativeDim = undefined; // reset dimensions of templates rendered with content or if image changes. afterwards, remove this flag.
this.layoutDoc._height = (width * nativeSize.nativeHeight) / nativeSize.nativeWidth;
}
},
@@ -224,7 +247,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
{ fireImmediately: true }
);
this._disposers.outpaint = reaction(
- () => this.Document[this.fieldKey + '_outpaintOriginalWidth'] !== undefined && !SnappingManager.ShiftKey,
+ () => this.outpaintOriginalSize?.width && !SnappingManager.ShiftKey,
complete => complete && this.openOutpaintPrompt(),
{ fireImmediately: true }
);
@@ -285,14 +308,15 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
DrawingFillHandler.drawingToImage(this.Document, 90, newPrompt(descText), 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.LayoutDataKey(layoutDoc);
- const targetDoc = layoutDoc[DocData];
- if (targetDoc[targetField] instanceof ImageField) {
+ const dropDoc = de.complete.docDragData?.draggedDocuments[0];
+ const dropDocFieldKey = Doc.LayoutDataKey(dropDoc);
+ const dropDataDoc = dropDoc[DocData];
+ if (dropDataDoc[dropDocFieldKey] 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);
+ this.dataDoc.layout_resetNativeDim = true;
+ this.dataDoc[this.fieldKey] = ObjectField.MakeCopy(dropDataDoc[dropDocFieldKey] as ImageField);
+ Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(dropDataDoc), this.fieldKey);
+ Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(dropDataDoc), this.fieldKey);
}
}
added === false && e.preventDefault();
@@ -311,18 +335,17 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@undoBatch
setNativeSize = action(() => {
- const oldnativeWidth = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']);
+ const oldnativeWidth = this.imgNativeSize.nativeWidth;
const nscale = NumCast(this._props.PanelWidth()) * NumCast(this.layoutDoc._freeform_scale, 1);
const nw = nscale / oldnativeWidth;
- this.dataDoc[this.fieldKey + '_nativeHeight'] = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) * nw;
- this.dataDoc[this.fieldKey + '_nativeWidth'] = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) * nw;
+ this.imgNativeSize = { nativeWidth: this.imgNativeSize.nativeWidth * nw, nativeHeight: this.imgNativeSize.nativeHeight * nw };
this.dataDoc.freeform_panX = nw * NumCast(this.dataDoc.freeform_panX);
this.dataDoc.freeform_panY = nw * NumCast(this.dataDoc.freeform_panY);
this.dataDoc.freeform_panX_max = this.dataDoc.freeform_panX_max ? nw * NumCast(this.dataDoc.freeform_panX_max) : undefined;
this.dataDoc.freeform_panX_min = this.dataDoc.freeform_panX_min ? nw * NumCast(this.dataDoc.freeform_panX_min) : undefined;
this.dataDoc.freeform_panY_max = this.dataDoc.freeform_panY_max ? nw * NumCast(this.dataDoc.freeform_panY_max) : undefined;
this.dataDoc.freeform_panY_min = this.dataDoc.freeform_panY_min ? nw * NumCast(this.dataDoc.freeform_panY_min) : undefined;
- const newnativeWidth = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']);
+ const newnativeWidth = this.imgNativeSize.nativeWidth;
DocListCast(this.dataDoc[this.annotationKey]).forEach(doc => {
doc.x = (NumCast(doc.x) / oldnativeWidth) * newnativeWidth;
doc.y = (NumCast(doc.y) / oldnativeWidth) * newnativeWidth;
@@ -334,13 +357,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
});
@undoBatch
rotate = action(() => {
- const nw = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']);
- const nh = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']);
+ const nativeSize = this.imgNativeSize;
const w = this.layoutDoc._width;
const h = this.layoutDoc._height;
this.dataDoc[this.fieldKey + '_rotation'] = (NumCast(this.dataDoc[this.fieldKey + '_rotation']) + 90) % 360;
- this.dataDoc[this.fieldKey + '_nativeWidth'] = nh;
- this.dataDoc[this.fieldKey + '_nativeHeight'] = nw;
+ this.imgNativeSize = { nativeWidth: nativeSize.nativeHeight, nativeHeight: nativeSize.nativeWidth }; // swap width and height
this.layoutDoc._width = h;
this.layoutDoc._height = w;
});
@@ -356,7 +377,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
const anchy = NumCast(cropping.y);
const anchw = NumCast(cropping._width);
const anchh = NumCast(cropping._height);
- const viewScale = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth']) / anchw;
+ const viewScale = this.nativeSize.nativeWidth / anchw;
cropping.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width);
cropping.y = NumCast(this.Document.y);
cropping.onClick = undefined;
@@ -418,11 +439,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@action
cancelOutpaintPrompt = () => {
- const origWidth = NumCast(this.Document[this.fieldKey + '_outpaintOriginalWidth']);
- const origHeight = NumCast(this.Document[this.fieldKey + '_outpaintOriginalHeight']);
- this.Document._width = origWidth;
- this.Document._height = origHeight;
+ [this.Document._width, this.Document._height] = [this.oupaintOriginalSize.width, this.oupaintOriginalSize.height];
this._outpaintingInProgress = false;
+ this.outpaintOriginalSize = undefined;
this.closeOutpaintPrompt();
};
@@ -470,8 +489,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
loadingOverlay.innerHTML = '<div style="color: white; font-size: 16px;">Generating outpainted image...</div>';
this._mainCont?.appendChild(loadingOverlay);
- const origWidth = NumCast(this.Document[this.fieldKey + '_outpaintOriginalWidth']);
- const origHeight = NumCast(this.Document[this.fieldKey + '_outpaintOriginalHeight']);
+ const { width: origWidth, height: origHeight } = this.oupaintOriginalSize;
const response = await Networking.PostToServer('/outpaintImage', {
imageUrl: currentPath,
prompt: customPrompt,
@@ -508,8 +526,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
this.Document.$ai = true;
this.Document.$ai_outpainted = true;
this.Document.$ai_outpaint_prompt = customPrompt;
- this.Document[this.fieldKey + '_outpaintOriginalWidth'] = undefined;
- this.Document[this.fieldKey + '_outpaintOriginalHeight'] = undefined;
+ this.outpaintOriginalSize = undefined;
} else {
this.cancelOutpaintPrompt();
alert('Failed to receive a valid image URL from server.');
@@ -722,8 +739,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@computed get nativeSize() {
TraceMobx();
if (this.paths.length && this.paths[0].includes(DefaultPath)) return { nativeWidth: NumCast(this.layoutDoc._width), nativeHeight: NumCast(this.layoutDoc._height), nativeOrientation: 0 };
- const nativeWidth = NumCast(this.dataDoc[this.fieldKey + '_nativeWidth'], NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth'], 500));
- const nativeHeight = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight'], NumCast(this.layoutDoc[this.fieldKey + '_nativeHeight'], 500));
+ const { nativeWidth, nativeHeight } = this.imgNativeSize;
const nativeOrientation = NumCast(this.dataDoc[this.fieldKey + '_nativeOrientation'], 1);
return { nativeWidth, nativeHeight, nativeOrientation };
}
@@ -743,7 +759,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
@computed get overlayImageIcon() {
const usePath = this.layoutDoc[`_${this.fieldKey}_usePath`];
- return (
+ return this._regenerateLoading ? null : (
<Tooltip
title={
<div className="dash-tooltip">
@@ -785,7 +801,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
);
}
@computed get regenerateImageIcon() {
- return (
+ return this._regenerateLoading ? null : (
<Tooltip title={'click to show AI generations. Drop an image on to create a new generation'}>
<div
className="imageBox-regenerateDropTarget"
@@ -874,7 +890,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
transform,
transformOrigin,
width: this._outpaintAlign ? 'max-content' : this._outpaintAlign ? '100%' : undefined,
- height: this._outpaintVAlign ? 'max-content' : this.Document[this.fieldKey + '_outpaintOriginalWidth'] !== undefined ? '100%' : undefined,
+ height: this._outpaintVAlign ? 'max-content' : this.outpaintOriginalSize?.width ? '100%' : undefined,
}}
onError={action(e => (this._error = e.toString()))}
draggable={false}
@@ -997,6 +1013,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
return { width, height };
};
savedAnnotations = () => this._savedAnnotations;
+ rejectDrop = (de: DragManager.DropEvent, subView?: DocumentView | undefined) => (this.dataDoc[this.fieldKey] === undefined ? true : (this._props.rejectDrop?.(de, subView) ?? false));
render() {
TraceMobx();
const borderRad = this._props.styleProvider?.(this.layoutDoc, this._props, StyleProp.BorderRounding) as string;
@@ -1040,7 +1057,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
ScreenToLocalTransform={this.screenToLocalTransform}
select={emptyFunction}
focus={this.focus}
- rejectDrop={this._props.rejectDrop}
+ rejectDrop={this.rejectDrop}
getScrollHeight={this.getScrollHeight}
NativeDimScaling={returnOne}
isAnyChildContentActive={returnFalse}
@@ -1102,8 +1119,11 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
if (result instanceof Error) {
alert('Error uploading files - possibly due to unsupported file types');
} else {
- this.dataDoc[this.fieldKey] = new ImageField(result.accessPaths.agnostic.client);
- !(result instanceof Error) && DocUtils.assignUploadInfo(result, this.dataDoc);
+ runInAction(() => {
+ this.dataDoc.layout_resetNativeDim = true;
+ !(result instanceof Error) && DocUtils.assignUploadInfo(result, this.dataDoc, this.fieldKey);
+ this.dataDoc[this.fieldKey] = new ImageField(result.accessPaths.agnostic.client);
+ });
}
disposer();
} else {