diff options
Diffstat (limited to 'src/client/views/DocumentDecorations.tsx')
-rw-r--r-- | src/client/views/DocumentDecorations.tsx | 158 |
1 files changed, 127 insertions, 31 deletions
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 54e050f9f..d7ff0d06a 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -1,6 +1,7 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { Tooltip } from '@mui/material'; +import { DimensionField } from '../../fields/DimensionField'; import { IconButton } from '@dash/components'; import { action, computed, makeObservable, observable, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -473,6 +474,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); @@ -491,17 +494,135 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora !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 + + // Special handling for shift+click (outpainting mode) + if (e.shiftKey && DocumentView.Selected().some(dv => dv.ComponentView instanceof ImageBox)) { + DocumentView.Selected().forEach(docView => { + if (docView.ComponentView instanceof ImageBox) { + // Set flag for outpainting mode + docView.Document._outpaintingResize = true; + + // Adjust only the document dimensions without scaling internal content + this.resizeViewForOutpainting(docView, refPt, scale, { dragHdl, shiftKey: e.shiftKey }); + } + else { + // Handle regular resize for non-image components + e.ctrlKey && !Doc.NativeHeight(docView.Document) && docView.toggleNativeDimensions(); + const hasFixedAspect = this.hasFixedAspect(docView.Document); + const scaleAspect = {x:scale.x === 1 && hasFixedAspect ? scale.y : scale.x, y: scale.x !== 1 && hasFixedAspect ? scale.x : scale.y}; + this.resizeView(docView, refPt, scaleAspect, { dragHdl, ctrlKey: e.ctrlKey }); + } + }); + } else { + // Regular resize behavior (existing code) + 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 })); + } + await new Promise<void>(res => { setTimeout(() => { res(this._interactionLock = undefined)})}); - }); // prettier-ignore + }); 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; + } + + if (!doc._outpaintingOriginalWidth || !doc._outpaintingOriginalHeight) { + doc._outpaintingOriginalWidth = NumCast(doc._width); + doc._outpaintingOriginalHeight = NumCast(doc._height); + + // Initialize or update the _originalDims ObjectField correctly + doc._originalDims = new DimensionField(doc._outpaintingOriginalWidth, doc._outpaintingOriginalHeight); + } + + // 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(); + + // Trigger outpainting + doc._needsOutpainting = true; + + // Store metadata needed for outpainting + doc._outpaintingMetadata = JSON.stringify({ + originalWidth: doc._outpaintingOriginalWidth, + originalHeight: doc._outpaintingOriginalHeight, + newWidth, + newHeight, + scaleX: scale.x, + scaleY: scale.y, + anchorHandle: opts.dragHdl + }); + }; + + @action + onPointerUp = (): void => { + SnappingManager.SetIsResizing(undefined); + SnappingManager.clearSnapLines(); + + // Check if any outpainting needs to be processed + DocumentView.Selected().forEach(view => { + if (view.Document._needsOutpainting && view.ComponentView instanceof ImageBox) { + // Trigger outpainting process in the ImageBox component + (view.ComponentView as ImageBox).processOutpainting(); + + // Clear flags + view.Document._needsOutpainting = false; + view.Document._outpaintingResize = false; + } + }); + + 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[DocData].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 // @@ -606,31 +727,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[DocData].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]; |