diff options
Diffstat (limited to 'src/client/views/collections/collectionFreeForm')
| -rw-r--r-- | src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 66 | ||||
| -rw-r--r-- | src/client/views/collections/collectionFreeForm/MarqueeView.tsx | 4 |
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); |
