From 64a9a1a982ec3f11adfed68cc0f18eb61059aff8 Mon Sep 17 00:00:00 2001
From: sharkiecodes <lanyi_stroud@brown.edu>
Date: Sun, 11 May 2025 22:58:07 -0400
Subject: integrated outpainting with scrapbooks

---
 src/client/views/DocumentDecorations.tsx | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index ab665e984..94e5e662c 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -36,6 +36,7 @@ import { ImageBox } from './nodes/ImageBox';
 import { OpenWhere, OpenWhereMod } from './nodes/OpenWhere';
 import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 import { TagsView } from './TagsView';
+import { ScrapbookBox } from './nodes/scrapbook/ScrapbookBox';
 
 interface DocumentDecorationsProps {
     PanelWidth: number;
@@ -446,7 +447,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
     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)
+            .filter(dv => e.shiftKey && dv.ComponentView instanceof ImageBox || dv.ComponentView instanceof ScrapbookBox)
             .forEach(dv => {
                 dv.Document[dv.ComponentView!.fieldKey + '_outpaintOriginalWidth'] = NumCast(dv.Document._width);
                 dv.Document[dv.ComponentView!.fieldKey + '_outpaintOriginalHeight'] = NumCast(dv.Document._height);
@@ -502,7 +503,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
                 this._interactionLock = true;
                 this._snapPt = thisPt;
 
-                const outpainted = e.shiftKey ? DocumentView.Selected().filter(dv => dv.ComponentView instanceof ImageBox) : [];
+                const outpainted = e.shiftKey ? DocumentView.Selected().filter(dv => dv.ComponentView instanceof ImageBox || dv.ComponentView instanceof ScrapbookBox) : [];
                 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)
@@ -765,7 +766,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
         const rotation = DocumentView.Selected().length === 1 ? seldocview.screenToContentsTransform().inverse().RotateDeg : 0;
 
         // Radius constants
-        const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof FormattedTextBox || seldocview.ComponentView instanceof CollectionFreeFormView;
+        const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof ScrapbookBox || seldocview.ComponentView instanceof FormattedTextBox || seldocview.ComponentView instanceof CollectionFreeFormView;
         const borderRadius = numberValue(Cast(seldocview.Document.layout_borderRounding, 'string', null));
         const docMax = Math.min(NumCast(seldocview.Document._width) / 2, NumCast(seldocview.Document._height) / 2);
         const maxDist = Math.min((this.Bounds.r - this.Bounds.x) / 2, (this.Bounds.b - this.Bounds.y) / 2);
-- 
cgit v1.2.3-70-g09d2


From b4db1e2467337468139d0e92ef94799c4143a0fc Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 11 Jun 2025 12:43:16 -0400
Subject: added outpaintable method to streamline determining which docs can be
 outpainted.

---
 src/client/views/DocumentDecorations.tsx          |  8 ++++----
 src/client/views/ViewBoxInterface.ts              |  1 +
 src/client/views/nodes/ImageBox.tsx               | 10 ++++------
 src/client/views/nodes/scrapbook/ScrapbookBox.tsx |  2 ++
 4 files changed, 11 insertions(+), 10 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index f36312056..383960444 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -1,7 +1,7 @@
+import { IconButton } from '@dash/components';
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Tooltip } from '@mui/material';
-import { IconButton } from '@dash/components';
 import { action, computed, makeObservable, observable, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as React from 'react';
@@ -27,6 +27,7 @@ import './DocumentDecorations.scss';
 import { InkStrokeProperties } from './InkStrokeProperties';
 import { InkingStroke } from './InkingStroke';
 import { ObservableReactComponent } from './ObservableReactComponent';
+import { TagsView } from './TagsView';
 import { CollectionDockingView } from './collections/CollectionDockingView';
 import { CollectionFreeFormView } from './collections/collectionFreeForm';
 import { Colors } from './global/globalEnums';
@@ -35,7 +36,6 @@ import { DocumentView } from './nodes/DocumentView';
 import { ImageBox } from './nodes/ImageBox';
 import { OpenWhere, OpenWhereMod } from './nodes/OpenWhere';
 import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
-import { TagsView } from './TagsView';
 import { ScrapbookBox } from './nodes/scrapbook/ScrapbookBox';
 
 interface DocumentDecorationsProps {
@@ -431,7 +431,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
     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 || dv.ComponentView instanceof ScrapbookBox)
+            .filter(dv => e.shiftKey && dv.ComponentView?.isOutpaintable?.())
             .forEach(dv => {
                 dv.Document[dv.ComponentView!.fieldKey + '_outpaintOriginalWidth'] = NumCast(dv.Document._width);
                 dv.Document[dv.ComponentView!.fieldKey + '_outpaintOriginalHeight'] = NumCast(dv.Document._height);
@@ -487,7 +487,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
                 this._interactionLock = true;
                 this._snapPt = thisPt;
 
-                const outpainted = e.shiftKey ? DocumentView.Selected().filter(dv => dv.ComponentView instanceof ImageBox || dv.ComponentView instanceof ScrapbookBox) : [];
+                const outpainted = e.shiftKey ? DocumentView.Selected().filter(dv => dv.ComponentView?.isOutpaintable?.()) : [];
                 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)
diff --git a/src/client/views/ViewBoxInterface.ts b/src/client/views/ViewBoxInterface.ts
index b532dfe35..83e395867 100644
--- a/src/client/views/ViewBoxInterface.ts
+++ b/src/client/views/ViewBoxInterface.ts
@@ -25,6 +25,7 @@ export abstract class ViewBoxInterface<P> extends ObservableReactComponent<React
     hasChildDocs?: () => Doc[];
     docEditorView?: () => void;
     autoTag?: () => void; // auto tag the document
+    isOutpaintable?: () => boolean; // can document be resized and outpainted
     showSmartDraw?: (x: number, y: number, regenerate?: boolean) => void;
     updateIcon?: (usePanelDimensions?: boolean) => Promise<void>; // updates the icon representation of the document
     getAnchor?: (addAsAnnotation: boolean, pinData?: PinProps) => Doc; // returns an Anchor Doc that represents the current state of the doc's componentview (e.g., the current playhead location of a an audio/video box)
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index d7e21b0a6..a99421f6d 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -262,9 +262,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         }
     };
 
-    handleSelection = async (selection: string) => {
-        this._searchInput = selection;
-    };
+    handleSelection = async (selection: string) => (this._searchInput = selection);
 
     drop = undoable(
         action((e: Event, de: DragManager.DropEvent) => {
@@ -429,9 +427,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     };
 
     @action
-    handlePromptChange = (val: string | number) => {
-        this._outpaintPromptInput = '' + val;
-    };
+    handlePromptChange = (val: string | number) => (this._outpaintPromptInput = '' + val);
 
     @action
     submitOutpaintPrompt = () => {
@@ -532,6 +528,8 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         return this._props.PanelWidth() / this._props.PanelHeight() < this.nativeSize.nativeWidth / this.nativeSize.nativeHeight;
     }
 
+    isOutpaintable = () => true;
+
     componentUI = (/* boundsLeft: number, boundsTop: number*/) =>
         !this._showOutpaintPrompt ? null : (
             <div
diff --git a/src/client/views/nodes/scrapbook/ScrapbookBox.tsx b/src/client/views/nodes/scrapbook/ScrapbookBox.tsx
index 94522c979..2db76c76f 100644
--- a/src/client/views/nodes/scrapbook/ScrapbookBox.tsx
+++ b/src/client/views/nodes/scrapbook/ScrapbookBox.tsx
@@ -174,6 +174,8 @@ export class ScrapbookBox extends ViewBoxAnnotatableComponent<FieldViewProps>()
         );
     }
 
+    isOutpaintable = () => true;
+
     @action
     generateAiImage = (prompt: string) => {
         this._loading = true;
-- 
cgit v1.2.3-70-g09d2


From bb7315dab4ba6da444e6a73820aed86bbdb82522 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 19 Jun 2025 15:22:49 -0400
Subject: from last

---
 src/client/views/DocumentDecorations.tsx | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

(limited to 'src/client/views/DocumentDecorations.tsx')

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 9172a3734..7a9f6c514 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -33,10 +33,7 @@ import { CollectionFreeFormView } from './collections/collectionFreeForm';
 import { Colors } from './global/globalEnums';
 import { CollectionFreeFormDocumentView } from './nodes/CollectionFreeFormDocumentView';
 import { DocumentView } from './nodes/DocumentView';
-import { ImageBox } from './nodes/ImageBox';
 import { OpenWhere, OpenWhereMod } from './nodes/OpenWhere';
-import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
-import { ScrapbookBox } from './nodes/scrapbook/ScrapbookBox';
 
 interface DocumentDecorationsProps {
     PanelWidth: number;
@@ -751,7 +748,7 @@ export class DocumentDecorations extends ObservableReactComponent<DocumentDecora
         const rotation = DocumentView.Selected().length === 1 ? seldocview.screenToContentsTransform().inverse().RotateDeg : 0;
 
         // Radius constants
-        const useRounding = seldocview.ComponentView instanceof ImageBox || seldocview.ComponentView instanceof ScrapbookBox || seldocview.ComponentView instanceof FormattedTextBox || seldocview.ComponentView instanceof CollectionFreeFormView;
+        const useRounding = seldocview.ComponentView?.showBorderRounding?.();
         const borderRadius = numberValue(Cast(seldocview.Document.layout_borderRounding, 'string', null));
         const docMax = Math.min(NumCast(seldocview.Document._width) / 2, NumCast(seldocview.Document._height) / 2);
         const maxDist = Math.min((this.Bounds.r - this.Bounds.x) / 2, (this.Bounds.b - this.Bounds.y) / 2);
-- 
cgit v1.2.3-70-g09d2

