From 4c768162e0436115a05b9c8b0e4d837d626d45ba Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 30 Oct 2024 18:54:52 -0400
Subject: reworked how context menu buttons for ink and text work. added
 disableMixBlend for making transparent docs not use 'multiply'.

---
 src/client/views/nodes/VideoBox.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

(limited to 'src/client/views/nodes/VideoBox.tsx')

diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index de51f6447..3bf7de2fe 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -776,7 +776,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
 
     // starts marquee selection
     marqueeDown = (e: React.PointerEvent) => {
-        if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) === 1 && this._props.isContentActive() && ![InkTool.Highlighter, InkTool.Pen].includes(Doc.ActiveTool)) {
+        if (!e.altKey && e.button === 0 && NumCast(this.layoutDoc._freeform_scale, 1) === 1 && this._props.isContentActive() && Doc.ActiveTool !== InkTool.Ink) {
             setupMoveUpEvents(
                 this,
                 e,
-- 
cgit v1.2.3-70-g09d2


From 93ee735e435de5949a0eec54c07537c4de2eedf4 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 7 Jan 2025 01:24:55 -0500
Subject: fixed pdfs/marqueeAnnotator so that you can add rectangle
 annotations.

---
 src/client/views/MarqueeAnnotator.tsx            |  5 ++--
 src/client/views/nodes/DataVizBox/DataVizBox.tsx |  1 +
 src/client/views/nodes/ImageBox.tsx              |  6 ++---
 src/client/views/nodes/PDFBox.scss               | 11 ++++++++
 src/client/views/nodes/PDFBox.tsx                | 34 +++++++++++-------------
 src/client/views/nodes/VideoBox.tsx              |  1 +
 src/client/views/nodes/WebBox.tsx                |  1 +
 src/client/views/pdf/PDFViewer.tsx               | 25 +++++++++--------
 8 files changed, 48 insertions(+), 36 deletions(-)

(limited to 'src/client/views/nodes/VideoBox.tsx')

diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx
index fa1123a2d..02516264c 100644
--- a/src/client/views/MarqueeAnnotator.tsx
+++ b/src/client/views/MarqueeAnnotator.tsx
@@ -15,18 +15,19 @@ import './MarqueeAnnotator.scss';
 import { DocumentView } from './nodes/DocumentView';
 import { ObservableReactComponent } from './ObservableReactComponent';
 import { AnchorMenu } from './pdf/AnchorMenu';
+import { Transform } from '../util/Transform';
 
 export interface MarqueeAnnotatorProps {
     Document: Doc;
     down?: number[];
     scrollTop: number;
-    isNativeScaled?: boolean;
     scaling?: () => number;
     annotationLayerScaling?: () => number;
     annotationLayerScrollTop: number;
     containerOffset?: () => number[];
     marqueeContainer: HTMLDivElement;
     docView: () => DocumentView;
+    screenTransform: () => Transform;
     savedAnnotations: () => ObservableMap<number, (HTMLDivElement & { marqueeing?: boolean })[]>;
     selectionText: () => string;
     annotationLayer: HTMLDivElement;
@@ -157,7 +158,7 @@ export class MarqueeAnnotator extends ObservableReactComponent<MarqueeAnnotatorP
     //    4) reattach the vector to the center of the bounding box
     getTransformedScreenPt = (down: number[]) => {
         const { marqueeContainer } = this.props;
-        const containerXf = this.props.isNativeScaled ? this.props.docView().screenToContentsTransform() : this.props.docView().screenToViewTransform();
+        const containerXf = this.props.screenTransform();
         const boundingRect = marqueeContainer.getBoundingClientRect();
         const center = { x: boundingRect.x + boundingRect.width / 2, y: boundingRect.y + boundingRect.height / 2 };
         const downVec = Utils.rotPt(down[0] - center.x,  
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 7026c3b01..b874d077b 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -832,6 +832,7 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         annotationLayerScrollTop={NumCast(this.Document._layout_scrollTop)}
                         scaling={returnOne}
                         docView={this.DocumentView}
+                        screenTransform={this.DocumentView().screenToViewTransform}
                         addDocument={this.sidebarAddDocument}
                         finishMarquee={this.finishMarquee}
                         savedAnnotations={this.savedAnnotations}
diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx
index 423a73f44..de8a9ad21 100644
--- a/src/client/views/nodes/ImageBox.tsx
+++ b/src/client/views/nodes/ImageBox.tsx
@@ -39,7 +39,6 @@ import { FocusViewOptions } from './FocusViewOptions';
 import './ImageBox.scss';
 import { OpenWhere } from './OpenWhere';
 import { Upload } from '../../../server/SharedMediaTypes';
-import { ImageUtils } from '../../util/Import & Export/ImageUtils';
 
 export class ImageEditorData {
     // eslint-disable-next-line no-use-before-define
@@ -268,7 +267,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 = NumCast(this.dataDoc[this.fieldKey + '_nativeHeight']) / anchh;
         cropping.title = 'crop: ' + this.Document.title;
         cropping.x = NumCast(this.Document.x) + NumCast(this.layoutDoc._width);
         cropping.y = NumCast(this.Document.y);
@@ -286,9 +285,9 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         croppingProto.data_nativeWidth = anchw;
         croppingProto.data_nativeHeight = anchh;
         croppingProto.freeform_scale = viewScale;
-        croppingProto.freeform_scale_min = viewScale;
         croppingProto.freeform_panX = anchx / viewScale;
         croppingProto.freeform_panY = anchy / viewScale;
+        croppingProto.freeform_scale_min = viewScale;
         croppingProto.freeform_panX_min = anchx / viewScale;
         croppingProto.freeform_panX_max = anchw / viewScale;
         croppingProto.freeform_panY_min = anchy / viewScale;
@@ -593,6 +592,7 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         annotationLayerScrollTop={0}
                         scaling={returnOne}
                         annotationLayerScaling={this._props.NativeDimScaling}
+                        screenTransform={this.DocumentView().screenToViewTransform}
                         docView={this.DocumentView}
                         addDocument={this.addDocument}
                         finishMarquee={this.finishMarquee}
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index 7bca1230f..f6908d5fd 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -250,6 +250,17 @@
     cursor: ew-resize;
     background: lightGray;
 }
+.pdfBox-container {
+    position: absolute;
+    transform-origin: top left;
+    top: 0;
+}
+.pdfBox-sidebarContainer {
+    position: absolute;
+    height: 100%;
+    right: 0;
+    top: 0;
+}
 
 .pdfBox-interactive {
     width: 100%;
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 1de4d2512..06b75e243 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -1,5 +1,5 @@
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
 import * as Pdfjs from 'pdfjs-dist';
 import 'pdfjs-dist/web/pdf_viewer.css';
@@ -40,8 +40,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     public static LayoutString(fieldKey: string) {
         return FieldView.LayoutString(PDFBox, fieldKey);
     }
+    static pdfcache = new Map<string, Pdfjs.PDFDocumentProxy>();
+    static pdfpromise = new Map<string, Promise<Pdfjs.PDFDocumentProxy>>();
     public static openSidebarWidth = 250;
     public static sidebarResizerWidth = 5;
+
     private _searchString: string = '';
     private _initialScrollTarget: Opt<Doc>;
     private _pdfViewer: PDFViewer | undefined;
@@ -63,11 +66,8 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
         const nh = Doc.NativeHeight(this.Document, this.dataDoc) || 1200;
         !this.Document._layout_fitWidth && (this.Document._height = NumCast(this.Document._width) * (nh / nw));
         if (this.pdfUrl) {
-            if (PDFBox.pdfcache.get(this.pdfUrl.url.href))
-                runInAction(() => {
-                    this._pdf = PDFBox.pdfcache.get(this.pdfUrl!.url.href);
-                });
-            else if (PDFBox.pdfpromise.get(this.pdfUrl.url.href))
+            this._pdf = PDFBox.pdfcache.get(this.pdfUrl.url.href);
+            !this._pdf &&
                 PDFBox.pdfpromise.get(this.pdfUrl.url.href)?.then(
                     action(pdf => {
                         this._pdf = pdf;
@@ -265,12 +265,12 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
     };
 
     @action
-    loaded = (nw: number, nh: number, np: number) => {
-        this.dataDoc[this._props.fieldKey + '_numPages'] = np;
-        Doc.SetNativeWidth(this.dataDoc, Math.max(Doc.NativeWidth(this.dataDoc), nw));
-        Doc.SetNativeHeight(this.dataDoc, nh);
+    loaded = (p: { width: number; height: number }, pages: number) => {
+        this.dataDoc[this._props.fieldKey + '_numPages'] = pages;
+        Doc.SetNativeWidth(this.dataDoc, Math.max(Doc.NativeWidth(this.dataDoc), p.width));
+        Doc.SetNativeHeight(this.dataDoc, p.height);
         this.layoutDoc._height = NumCast(this.layoutDoc._width) / (Doc.NativeAspect(this.dataDoc) || 1);
-        !this.Document._layout_fitWidth && (this.Document._height = NumCast(this.Document._width) * (nh / nw));
+        !this.Document._layout_fitWidth && (this.Document._height = NumCast(this.Document._width) * (p.height / p.width));
     };
 
     override search = action((searchString: string, bwd?: boolean, clear: boolean = false) => {
@@ -596,13 +596,11 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                 }}>
                 <div className="pdfBox-background" onPointerDown={e => this.sidebarBtnDown(e, false)} />
                 <div
+                    className="pdfBox-container"
                     style={{
                         width: `calc(${100 / viewScale}% - ${(this.sidebarWidth() / viewScale) * (this._previewWidth ? viewScale : 1)}px)`,
                         height: `${100 / viewScale}%`,
                         transform: `scale(${viewScale})`,
-                        position: 'absolute',
-                        transformOrigin: 'top left',
-                        top: 0,
                     }}>
                     <PDFViewer
                         {...this._props}
@@ -615,7 +613,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         focus={this.focus}
                         url={this.pdfUrl!.url.pathname}
                         anchorMenuClick={this.anchorMenuClick}
-                        loaded={!Doc.NativeAspect(this.dataDoc) ? this.loaded : undefined}
+                        loaded={Doc.NativeAspect(this.dataDoc) ? emptyFunction : this.loaded}
                         setPdfViewer={this.setPdfViewer}
                         addDocument={this.addDocument}
                         moveDocument={this.moveDocument}
@@ -624,14 +622,14 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                         crop={this.crop}
                     />
                 </div>
-                <div style={{ position: 'absolute', height: '100%', right: 0, top: 0, width: `calc(100 * ${this.sidebarWidth() / this._props.PanelWidth()}%` }}>{this.sidebarCollection}</div>
+                <div className="pdfBox-sidebarContainer" style={{ width: `calc(100 * ${this.sidebarWidth() / this._props.PanelWidth()}%` }}>
+                    {this.sidebarCollection}
+                </div>
                 {this.settingsPanel()}
             </div>
         );
     }
 
-    static pdfcache = new Map<string, Pdfjs.PDFDocumentProxy>();
-    static pdfpromise = new Map<string, Promise<Pdfjs.PDFDocumentProxy>>();
     render() {
         TraceMobx();
         const pdfView = !this._pdf ? null : this.renderPdfView;
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 3bf7de2fe..9adee53e8 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -1023,6 +1023,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                             scaling={returnOne}
                             annotationLayerScaling={this._props.NativeDimScaling}
                             docView={this.DocumentView}
+                            screenTransform={this.DocumentView().screenToViewTransform}
                             containerOffset={this.marqueeOffset}
                             addDocument={this.addDocWithTimecode}
                             finishMarquee={this.finishMarquee}
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index ffeb574e9..6026d9ca7 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -1196,6 +1196,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
                             scaling={this._props.NativeDimScaling}
                             addDocument={this.addDocumentWrapper}
                             docView={this.DocumentView}
+                            screenTransform={this.DocumentView().screenToViewTransform}
                             finishMarquee={this.finishMarquee}
                             savedAnnotations={this.savedAnnotationsCreator}
                             selectionText={this.selectionText}
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 722492e8d..ca7f72811 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -30,6 +30,7 @@ import { GPTPopup } from './GPTPopup/GPTPopup';
 import './PDFViewer.scss';
 import { GPTCallType, gptAPICall } from '../../apis/gpt/GPT';
 import ReactLoading from 'react-loading';
+import { Transform } from '../../util/Transform';
 
 interface IViewerProps extends FieldViewProps {
     pdfBox: PDFBox;
@@ -40,7 +41,7 @@ interface IViewerProps extends FieldViewProps {
     pdf: Pdfjs.PDFDocumentProxy;
     url: string;
     sidebarAddDoc: (doc: Doc | Doc[], sidebarKey?: string | undefined) => boolean;
-    loaded?: (nw: number, nh: number, np: number) => void;
+    loaded: (p: { width: number; height: number }, pages: number) => void;
     // eslint-disable-next-line no-use-before-define
     setPdfViewer: (view: PDFViewer) => void;
     anchorMenuClick?: () => undefined | ((anchor: Doc) => void);
@@ -151,24 +152,21 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
     }
 
     initialLoad = () => {
+        const page0or180 = (page: { rotate: number }) => page.rotate === 0 || page.rotate === 180;
         if (this._pageSizes.length === 0) {
             const devicePixelRatio = window.devicePixelRatio;
             document.documentElement?.style.setProperty('--devicePixelRatio', window.devicePixelRatio.toString()); // set so that css can use this to adjust various PDFJs divs
             Promise.all(
                 numberRange(this._props.pdf.numPages).map(i =>
-                    this._props.pdf.getPage(i + 1).then(page => {
-                        const page0or180 = page.rotate === 0 || page.rotate === 180;
-                        return {
-                            width: page.view[page0or180 ? 2 : 3] * devicePixelRatio - page.view[page0or180 ? 0 : 1] * devicePixelRatio,
-                            height: page.view[page0or180 ? 3 : 2] * devicePixelRatio - page.view[page0or180 ? 1 : 0] * devicePixelRatio,
-                        };
-                    })
+                    this._props.pdf.getPage(i + 1).then(page => ({
+                        width: (page.view[page0or180(page) ? 2 : 3] - page.view[page0or180(page) ? 0 : 1]) * devicePixelRatio,
+                        height: (page.view[page0or180(page) ? 3 : 2] - page.view[page0or180(page) ? 1 : 0]) * devicePixelRatio,
+                    }))
                 )
             ).then(
                 action(pages => {
                     this._pageSizes = pages;
-                    const lastPage = pages.lastElement();
-                    this._props.loaded?.(lastPage.width, lastPage.height, this._props.pdf.numPages);
+                    this._props.loaded(pages.lastElement(), this._props.pdf.numPages);
                     this.createPdfViewer();
                 })
             );
@@ -599,6 +597,7 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
     }
     savedAnnotations = () => this._savedAnnotations;
     addDocumentWrapper = (doc: Doc | Doc[]) => this._props.addDocument!(doc);
+    screenToMarqueeXf = () => this.props.pdfBox.DocumentView?.()?.screenToContentsTransform().scale(Pdfjs.PixelsPerInch.PDF_TO_CSS_UNITS) ?? Transform.Identity();
     render() {
         TraceMobx();
         return (
@@ -618,17 +617,17 @@ export class PDFViewer extends ObservableReactComponent<IViewerProps> {
                     {this.annotationLayer}
                     {this.overlayLayer}
                     {this._showWaiting ? <img alt="" className="pdfViewerDash-waiting" src="/assets/loading.gif" /> : null}
-                    {!this._mainCont.current || !this._annotationLayer.current ? null : (
+                    {!this._mainCont.current || !this._annotationLayer.current || !this.props.pdfBox.DocumentView ? null : (
                         <MarqueeAnnotator
                             ref={this._marqueeref}
                             Document={this._props.Document}
                             getPageFromScroll={this.getPageFromScroll}
                             anchorMenuClick={this._props.anchorMenuClick}
                             scrollTop={0}
-                            isNativeScaled
                             annotationLayerScrollTop={NumCast(this._props.Document._layout_scrollTop)}
                             addDocument={this.addDocumentWrapper}
-                            docView={this._props.pdfBox.DocumentView!}
+                            docView={this.props.pdfBox.DocumentView}
+                            screenTransform={this.screenToMarqueeXf}
                             finishMarquee={this.finishMarquee}
                             savedAnnotations={this.savedAnnotations}
                             selectionText={this.selectionText}
-- 
cgit v1.2.3-70-g09d2

