aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/collectionFreeForm
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections/collectionFreeForm')
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx66
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx4
2 files changed, 43 insertions, 27 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 51672578e..d6e95f97f 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -16,7 +16,7 @@ import { BoolCast, Cast, DocCast, FieldValue, NumCast, ScriptCast, StrCast } fro
import { ImageField } from '../../../../fields/URLField';
import { TraceMobx } from '../../../../fields/util';
import { GestureUtils } from '../../../../pen-gestures/GestureUtils';
-import { aggregateBounds, emptyFunction, intersectRect, returnFalse, setupMoveUpEvents, Utils } from '../../../../Utils';
+import { aggregateBounds, emptyFunction, intersectRect, returnFalse, returnTransparent, setupMoveUpEvents, Utils } from '../../../../Utils';
import { CognitiveServices } from '../../../cognitive_services/CognitiveServices';
import { Docs, DocUtils } from '../../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
@@ -61,6 +61,7 @@ export type collectionFreeformViewProps = {
scaleField?: string;
noOverlay?: boolean; // used to suppress docs in the overlay (z) layer (ie, for minimap since overlay doesn't scale)
engineProps?: any;
+ getScrollHeight?: () => number | undefined;
dontScaleFilter?: (doc: Doc) => boolean; // whether this collection should scale documents to fit their panel vs just scrolling them
dontRenderDocuments?: boolean; // used for annotation overlays which need to distribute documents into different freeformviews with different mixBlendModes depending on whether they are transparent or not.
// However, this screws up interactions since only the top layer gets events. so we render the freeformview a 3rd time with all documents in order to get interaction events (eg., marquee) but we don't actually want to display the documents.
@@ -363,10 +364,10 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const grouping = this.props.Document._useClusters ? NumCast(cd.cluster, -1) : NumCast(cd.group, -1);
if (grouping !== -1) {
const layoutDoc = Doc.Layout(cd);
- const cx = NumCast(cd.x) - this._clusterDistance;
- const cy = NumCast(cd.y) - this._clusterDistance;
- const cw = NumCast(layoutDoc._width) + 2 * this._clusterDistance;
- const ch = NumCast(layoutDoc._height) + 2 * this._clusterDistance;
+ const cx = NumCast(cd.x) - this._clusterDistance / 2;
+ const cy = NumCast(cd.y) - this._clusterDistance / 2;
+ const cw = NumCast(layoutDoc._width) + this._clusterDistance;
+ const ch = NumCast(layoutDoc._height) + this._clusterDistance;
return !layoutDoc.z && intersectRect({ left: cx, top: cy, width: cw, height: ch }, { left: probe[0], top: probe[1], width: 1, height: 1 }) ? grouping : cluster;
}
return cluster;
@@ -545,7 +546,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
case InkTool.None:
if (!(this.props.layoutEngine?.() || StrCast(this.layoutDoc._layoutEngine))) {
this._hitCluster = this.pickCluster(this.getTransform().transformPoint(e.clientX, e.clientY));
- setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, emptyFunction, false);
+ setupMoveUpEvents(this, e, this.onPointerMove, emptyFunction, emptyFunction, this._hitCluster !== -1 ? true : false);
}
break;
}
@@ -771,7 +772,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
} else if (!e.cancelBubble) {
if (this.tryDragCluster(e, this._hitCluster)) {
return true;
- } else this.pan(e);
+ }
+ this.pan(e);
}
return false;
};
@@ -1004,6 +1006,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (deltaScale * invTransform.Scale > 20) {
deltaScale = 20 / invTransform.Scale;
}
+ if (deltaScale < 1 && invTransform.Scale <= NumCast(this.rootDoc._viewScaleMin, 1) && this.isAnnotationOverlay) {
+ return;
+ }
if (deltaScale * invTransform.Scale < NumCast(this.rootDoc._viewScaleMin, 1) && this.isAnnotationOverlay) {
deltaScale = NumCast(this.rootDoc._viewScaleMin, 1) / invTransform.Scale;
}
@@ -1012,29 +1017,26 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (localTransform.Scale >= 0.05 || localTransform.Scale > this.zoomScaling()) {
const safeScale = Math.min(Math.max(0.05, localTransform.Scale), 20);
this.props.Document[this.scaleFieldKey] = Math.abs(safeScale);
- this.setPan(-localTransform.TranslateX / safeScale, -localTransform.TranslateY / safeScale);
+ this.setPan(-localTransform.TranslateX / safeScale, NumCast(this.props.Document.scrollTop) * safeScale || -localTransform.TranslateY / safeScale);
}
};
@action
onPointerWheel = (e: React.WheelEvent): void => {
+ if (this.Document._isGroup) return; // group style collections neither pan nor zoom
PresBox.Instance?.pauseAutoPres();
if (this.layoutDoc._Transform || DocListCast(Doc.MyOverlayDocs?.data).includes(this.props.Document) || this.props.Document.treeViewOutlineMode === TreeViewType.outline) return;
e.stopPropagation();
e.preventDefault();
switch (!e.ctrlKey ? Doc.UserDoc().freeformScrollMode : freeformScrollMode.Pan) {
case freeformScrollMode.Pan:
- // if shift is selected then zoom
+ // if ctrl is selected then zoom
if (e.ctrlKey) {
- if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) {
- // things that can scroll vertically should do that instead of zooming
- } else if (this.props.isContentActive(true) && !this.Document._isGroup) {
+ if (this.props.isContentActive(true)) {
!this.props.isAnnotationOverlayScrollable && this.zoom(e.clientX, e.clientY, e.deltaY); // if (!this.props.isAnnotationOverlay) // bcz: do we want to zoom in on images/videos/etc?
}
- // otherwise pan
- } else if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) {
- // things that can scroll vertically should do that instead of zooming
- } else if (this.props.isContentActive(true) && !this.Document._isGroup) {
+ } // otherwise pan
+ else if (this.props.isContentActive(true)) {
const dx = -e.deltaX;
const dy = -e.deltaY;
if (e.shiftKey) {
@@ -1046,9 +1048,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
break;
default:
case freeformScrollMode.Zoom:
- if (!e.ctrlKey && (this.props.Document.scrollHeight ?? this.props.DocumentView?.().ComponentView?.getScrollHeight?.()) !== undefined) {
- // things that can scroll vertically should do that instead of zooming
- } else if (this.props.isContentActive(true) && !this.Document._isGroup) {
+ if (this.props.isContentActive(true)) {
!this.props.isAnnotationOverlayScrollable && this.zoom(e.clientX, e.clientY, e.deltaY); // if (!this.props.isAnnotationOverlay) // bcz: do we want to zoom in on images/videos/etc?
}
break;
@@ -1096,7 +1096,26 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const minPanX = NumCast(this.rootDoc._panXMin, 0);
const minPanY = NumCast(this.rootDoc._panYMin, 0);
const newPanX = Math.min(minPanX + (1 - minScale / scale) * NumCast(this.rootDoc._panXMax, this.nativeWidth), Math.max(minPanX, panX));
- const newPanY = Math.min(this.props.Document.scrollHeight !== undefined ? NumCast(this.Document.scrollHeight) : minPanY + (1 - minScale / scale) * NumCast(this.rootDoc._panYMax, this.nativeHeight), Math.max(minPanY, panY));
+ const fitYscroll = (((this.nativeHeight / this.nativeWidth) * this.props.PanelWidth() - this.props.PanelHeight()) * this.props.ScreenToLocalTransform().Scale) / minScale;
+ const nativeHeight = (this.props.PanelHeight() / this.props.PanelWidth() / (this.nativeHeight / this.nativeWidth)) * this.nativeHeight;
+ const maxScrollTop = this.nativeHeight / this.props.ScreenToLocalTransform().Scale - this.props.PanelHeight();
+ const maxPanY =
+ minPanY + // minPanY + scrolling introduced by view scaling + scrolling introduced by fitWidth
+ (1 - minScale / scale) * NumCast(this.rootDoc._panYMax, nativeHeight) +
+ (!this.props.getScrollHeight?.() ? fitYscroll : 0); // when not zoomed, scrolling is handled via a scrollbar, not panning
+ let newPanY = Math.max(minPanY, Math.min(maxPanY, panY));
+ if (NumCast(this.rootDoc.scrollTop) && NumCast(this.rootDoc._viewScale, minScale) !== minScale) {
+ const relTop = NumCast(this.rootDoc.scrollTop) / maxScrollTop;
+ this.rootDoc.scrollTop = undefined;
+ newPanY = minPanY + relTop * (maxPanY - minPanY);
+ } else if (fitYscroll && this.rootDoc.scrollTop === undefined && NumCast(this.rootDoc._viewScale, minScale) === minScale) {
+ const maxPanY = minPanY + fitYscroll;
+ const relTop = (panY - minPanY) / (maxPanY - minPanY);
+ setTimeout(() => {
+ this.rootDoc.scrollTop = relTop * maxScrollTop;
+ }, 10);
+ newPanY = minPanY;
+ }
!this.Document._verticalScroll && (this.Document._panX = this.isAnnotationOverlay ? newPanX : panX);
!this.Document._horizontalScroll && (this.Document._panY = this.isAnnotationOverlay ? newPanY : panY);
}
@@ -1169,7 +1188,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
// if (SelectionManager.Views().length !== 1 || SelectionManager.Views()[0].Document !== doc) {
// SelectionManager.DeselectAll();
// }
- if (this.props.Document.scrollHeight || this.props.Document.scrollTop !== undefined || this.props.Document.currentTimecode !== undefined || doc.type === DocumentType.MARKER) {
+ if (this.props.getScrollHeight || this.props.Document.scrollTop !== undefined || this.props.Document.currentTimecode !== undefined || doc.type === DocumentType.MARKER) {
this.props.focus(doc, options);
} else {
const xfToCollection = options?.docTransform ?? Transform.Identity();
@@ -2033,10 +2052,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
: (this.props.pointerEvents?.() as any),
transform: `scale(${this.nativeDimScaling || 1})`,
width: `${100 / (this.nativeDimScaling || 1)}%`,
- height:
- this.isAnnotationOverlay && (this.Document.scrollHeight || this.props.DocumentView?.().ComponentView?.getScrollHeight?.())
- ? NumCast(this.Document.scrollHeight || this.props.DocumentView?.().ComponentView?.getScrollHeight?.())
- : `${100 / (this.nativeDimScaling || 1)}%`, // : this.isAnnotationOverlay ? (this.Document.scrollHeight ? this.Document.scrollHeight : "100%") : this.props.PanelHeight()
+ height: this.props.getScrollHeight?.() ?? `${100 / (this.nativeDimScaling || 1)}%`,
}}>
{this._firstRender ? this.placeholder : this.marqueeView}
{this.props.noOverlay ? null : <CollectionFreeFormOverlayView elements={this.elementFunc} />}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 0b7854926..bc3b17cd9 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -431,8 +431,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@undoBatch
@action
- collection = (e: KeyboardEvent | React.PointerEvent | undefined, group?: boolean) => {
- const selected = this.marqueeSelect(false);
+ collection = (e: KeyboardEvent | React.PointerEvent | undefined, group?: boolean, selection?: Doc[]) => {
+ const selected = selection ?? this.marqueeSelect(false);
const activeFrame = selected.reduce((v, d) => v ?? Cast(d._activeFrame, 'number', null), undefined as number | undefined);
if (e instanceof KeyboardEvent ? 'cg'.includes(e.key) : true) {
this.props.removeDocument?.(selected);