aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/DocumentDecorations.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/DocumentDecorations.tsx')
-rw-r--r--src/client/views/DocumentDecorations.tsx144
1 files changed, 96 insertions, 48 deletions
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 120467e8a..ab665e984 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -240,7 +240,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
} else {
// if Doc is in the sticker palette, remove the flag indicating that it's saved
const dragFactory = DocCast(iconView.Document.dragFactory);
- if (dragFactory && DocCast(dragFactory.cloneOf).savedAsSticker) DocCast(dragFactory.cloneOf).savedAsSticker = undefined;
+ if (dragFactory && DocCast(dragFactory.cloneOf)?.savedAsSticker) DocCast(dragFactory.cloneOf)!.savedAsSticker = undefined;
// if this is a face Annotation doc, then just hide it.
if (iconView.Document.annotationOn && iconView.Document.face) iconView.Document.hidden = true;
@@ -445,6 +445,12 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
@action
onPointerDown = (e: React.PointerEvent): void => {
SnappingManager.SetIsResizing(DocumentView.Selected().lastElement()?.Document[Id]); // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them
+ DocumentView.Selected()
+ .filter(dv => e.shiftKey && dv.ComponentView instanceof ImageBox)
+ .forEach(dv => {
+ 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();
const id = (this._resizeHdlId = e.currentTarget.className);
@@ -473,6 +479,8 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
const tl = docView.screenToContentsTransform().inverse().transformPoint(0, 0);
return project([e.clientX + this._offset.x, e.clientY + this._offset.y], tl, [tl[0] + fixedAspect, tl[1] + 1]);
};
+
+ // Modify the onPointerMove method to handle shift+click during resize
onPointerMove = (e: PointerEvent): boolean => {
const first = DocumentView.Selected()[0];
const effectiveAcl = GetEffectiveAcl(first.Document);
@@ -482,26 +490,92 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
const dragHdl = this._resizeHdlId.split(' ')[0].replace('documentDecorations-', '').replace('Resizer', '');
const thisPt = // do snapping of drag point
- fixedAspect && (dragHdl === 'bottomRight' || dragHdl === 'topLeft')
+ fixedAspect && (dragHdl === 'bottomRight' || dragHdl === 'topLeft') && e.ctrlKey
? DragManager.snapDragAspect(this.projectDragToAspect(e, first, fixedAspect), fixedAspect)
: DragManager.snapDrag(e, -this._offset.x, -this._offset.y, this._offset.x, this._offset.y);
const { scale, refPt } = this.getResizeVals(thisPt, dragHdl);
- !this._interactionLock && runInAction(async () => { // resize selected docs if we're not in the middle of a resize (ie, throttle input events to frame rate)
- this._interactionLock = true;
- this._snapPt = thisPt;
- e.ctrlKey && (DocumentView.Selected().forEach(docView => !Doc.NativeHeight(docView.Document) && docView.toggleNativeDimensions()));
- const hasFixedAspect = DocumentView.Selected().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};
- DocumentView.Selected().forEach(docView =>
- this.resizeView(docView, refPt, scaleAspect, { dragHdl, ctrlKey:e.ctrlKey })); // prettier-ignore
- await new Promise<void>(res => { setTimeout(() => { res(this._interactionLock = undefined)})});
- }); // prettier-ignore
+ !this._interactionLock &&
+ runInAction(() => {
+ // resize selected docs if we're not in the middle of a resize (ie, throttle input events to frame rate)
+ this._interactionLock = true;
+ this._snapPt = thisPt;
+
+ 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();
+
+ // 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 }));
+
+ new Promise<void>(res => setTimeout(() => res((this._interactionLock = undefined))));
+ });
return false;
};
+ resizeViewForOutpainting = (docView: DocumentView, refPt: number[], scale: { x: number; y: number }, opts: { dragHdl: string; shiftKey: boolean }) => {
+ const doc = docView.Document;
+
+ if (doc.isGroup) {
+ DocListCast(doc.data)
+ .map(member => DocumentView.getDocumentView(member, docView)!)
+ .forEach(member => this.resizeViewForOutpainting(member, refPt, scale, opts));
+ doc.xPadding = NumCast(doc.xPadding) * scale.x;
+ doc.yPadding = NumCast(doc.yPadding) * scale.y;
+ return;
+ }
+
+ // Calculate new boundary dimensions
+ const originalWidth = NumCast(doc._width);
+ const originalHeight = NumCast(doc._height);
+ const newWidth = Math.max(NumCast(doc._width_min, 25), originalWidth * scale.x);
+ const newHeight = Math.max(NumCast(doc._height_min, 10), originalHeight * scale.y);
+
+ // Apply new dimensions
+ doc._width = newWidth;
+ doc._height = newHeight;
+
+ const refCent = docView.screenToViewTransform().transformPoint(refPt[0], refPt[1]);
+ 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 = () => {
+ SnappingManager.SetIsResizing(undefined);
+ SnappingManager.clearSnapLines();
+
+ this._resizeHdlId = '';
+ this._resizeUndo?.end();
+
+ // detect layout_autoHeight gesture and apply
+ DocumentView.Selected().forEach(view => {
+ NumCast(view.Document._height) < 20 && (view.layoutDoc._layout_autoHeight = true);
+ });
+ // need to change points for resize, or else rotation/control points will fail.
+ this._inkDragDocs
+ .map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] }))
+ .forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => {
+ doc.$data = new InkField(inkPts.map(
+ (ipt) => ({// (new x — oldx) + newWidth * (oldxpoint /oldWidth)
+ X: NumCast(doc.x) - x + (NumCast(doc._width) * ipt.X) / width,
+ Y: NumCast(doc.y) - y + (NumCast(doc._height) * ipt.Y) / height,
+ }))); // prettier-ignore
+ Doc.SetNativeWidth(doc, undefined);
+ Doc.SetNativeHeight(doc, undefined);
+ });
+ };
+
//
// determines how much to resize, and determines the resize reference point
//
@@ -529,7 +603,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
//
// resize a single DocumentView about the specified reference point, possibly setting/updating the native dimensions of the Doc
//
- resizeView = (docView: DocumentView, refPt: number[], scale: { x: number; y: number }, opts: { dragHdl: string; ctrlKey: boolean }) => {
+ resizeView = (docView: DocumentView, refPt: number[], scale: { x: number; y: number }, opts: { dragHdl: string; freezeNativeDims: boolean }) => {
const doc = docView.Document;
if (doc.isGroup) {
DocListCast(doc.data)
@@ -542,25 +616,24 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
const [nwidth, nheight] = [docView.nativeWidth, docView.nativeHeight];
const [initWidth, initHeight] = [NumCast(doc._width, 1), NumCast(doc._height)];
- const modifyNativeDim =
- (opts.ctrlKey && doc._layout_nativeDimEditable) || // e.g., PDF or web page
- (doc._layout_reflowHorizontal && opts.dragHdl !== 'bottom' && opts.dragHdl !== 'top') || // eg rtf or some web pages
- (doc._layout_reflowVertical && (opts.dragHdl === 'bottom' || opts.dragHdl === 'top' || opts.ctrlKey)); // eg rtf, web, pdf
- if (nwidth && nheight && !modifyNativeDim) {
- // eg., dragging right resizer on PDF -- enforce native dimensions because not expliclty overridden with ctrl or bottom resize drag
+ const cornerReflow = !opts.freezeNativeDims && doc._layout_reflowHorizontal && doc._layout_reflowVertical && ['topLeft', 'topRight', 'bottomLeft', 'bottomRight'].includes(opts.dragHdl);
+ const horizontalReflow = !opts.freezeNativeDims && doc._layout_reflowHorizontal && ['left', 'right'].includes(opts.dragHdl); // eg rtf or some web pages
+ const verticalReflow = !opts.freezeNativeDims && doc._layout_reflowVertical && ['bottom', 'top'].includes(opts.dragHdl); // eg rtf, web, pdf
+ // preserve aspect ratio if Doc has a native ize and drag won't cause reflow (eg, ctrl-dragging a Doc's corner doesn't allow reflow, or dragging right side of a PDF which isn't horizontally reflowable)
+ if (nwidth && nheight && !cornerReflow && !horizontalReflow && !verticalReflow) {
scale.x === 1 ? (scale.x = scale.y) : (scale.y = scale.x);
}
- if (['right', 'left', 'bottomRight'].includes(opts.dragHdl) && modifyNativeDim && Doc.NativeWidth(doc)) {
+ if ((horizontalReflow || cornerReflow) && Doc.NativeWidth(doc)) {
const setData = Doc.NativeWidth(doc[DocData]) === doc.nativeWidth;
- doc.nativeWidth = scale.x * Doc.NativeWidth(doc);
+ doc._nativeWidth = scale.x * Doc.NativeWidth(doc);
if (setData) Doc.SetNativeWidth(doc[DocData], NumCast(doc.nativeWidth));
if (doc._layout_reflowVertical && !NumCast(doc.nativeHeight)) {
doc._nativeHeight = (initHeight / initWidth) * nwidth; // initializes the nativeHeight for a PDF
}
}
- if (['bottom', 'top', 'bottomRight'].includes(opts.dragHdl) && modifyNativeDim && Doc.NativeHeight(doc)) {
- const setData = Doc.NativeHeight(doc[DocData]) === doc.nativeHeight && (!doc.layout_reflowVertical || opts.ctrlKey);
+ if ((verticalReflow || cornerReflow) && Doc.NativeHeight(doc)) {
+ const setData = Doc.NativeHeight(doc[DocData]) === doc.nativeHeight && !doc.layout_reflowVertical;
doc._nativeHeight = scale.y * Doc.NativeHeight(doc);
if (setData) Doc.SetNativeHeight(doc[DocData], NumCast(doc._nativeHeight));
}
@@ -606,31 +679,6 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
};
};
- @action
- onPointerUp = (): void => {
- SnappingManager.SetIsResizing(undefined);
- SnappingManager.clearSnapLines();
- this._resizeHdlId = '';
- this._resizeUndo?.end();
-
- // detect layout_autoHeight gesture and apply
- DocumentView.Selected().forEach(view => {
- NumCast(view.Document._height) < 20 && (view.layoutDoc._layout_autoHeight = true);
- });
- // need to change points for resize, or else rotation/control points will fail.
- this._inkDragDocs
- .map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] }))
- .forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => {
- doc.$data = new InkField(inkPts.map(
- (ipt) => ({// (new x — oldx) + newWidth * (oldxpoint /oldWidth)
- X: NumCast(doc.x) - x + (NumCast(doc._width) * ipt.X) / width,
- Y: NumCast(doc.y) - y + (NumCast(doc._height) * ipt.Y) / height,
- }))); // prettier-ignore
- Doc.SetNativeWidth(doc, undefined);
- Doc.SetNativeHeight(doc, undefined);
- });
- };
-
@computed get selectionTitle(): string {
if (DocumentView.Selected().length === 1) {
const selected = DocumentView.Selected()[0];