From e17b1bdb09bfcadc717e687b09d2c18596341a10 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 9 Feb 2023 21:15:58 -0500 Subject: fixed childLayoutString to work. made images capable of fitWidth. fixed animating data field pres changes. fixed lightbox to ignore annotations on collections. fixed double-click on icon to open in lightbox. added options for turning off ink labels, and opening ink in lightbox. fixed closing ink strokes by dragging. fixed drawing ink to use coord sys of starting point and to render ink the correct width and to honor GestureOverlay mode properly. . --- .../collectionFreeForm/CollectionFreeFormView.tsx | 66 ++++++++++++++-------- .../collections/collectionFreeForm/MarqueeView.tsx | 4 +- 2 files changed, 43 insertions(+), 27 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') 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 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= 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 { + 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 {this._firstRender ? this.placeholder : this.marqueeView} {this.props.noOverlay ? null : } 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 { - 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); -- cgit v1.2.3-70-g09d2 From 5aff8956fb5a48bd2188ffca9b650b378669b921 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 10 Feb 2023 14:59:27 -0500 Subject: changed ink masks to have a blur and to allow masks of different colors by adjusting the color value to have no blackness. --- src/client/util/InteractionUtils.tsx | 9 ++++++++- src/client/views/InkingStroke.tsx | 15 ++++++++------- .../collectionFreeForm/CollectionFreeFormView.scss | 2 +- 3 files changed, 17 insertions(+), 9 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx index 3cdf4dbd2..9591dbed3 100644 --- a/src/client/util/InteractionUtils.tsx +++ b/src/client/util/InteractionUtils.tsx @@ -107,7 +107,8 @@ export namespace InteractionUtils { pevents: string, opacity: number, nodefs: boolean, - downHdlr?: (e: React.PointerEvent) => void + downHdlr?: (e: React.PointerEvent) => void, + mask?: boolean ) { const pts = shape ? makePolygon(shape, points) : points; @@ -133,6 +134,11 @@ export namespace InteractionUtils { {/* setting the svg fill sets the arrowStart fill */} {nodefs ? null : ( + {!mask ? null : ( + + + + )} {arrowStart !== 'dot' && arrowEnd !== 'dot' ? null : ( @@ -168,6 +174,7 @@ export namespace InteractionUtils { style={{ // filter: drawHalo ? "url(#inkSelectionHalo)" : undefined, fill: fill && fill !== 'transparent' ? fill : 'none', + filter: mask ? `url(#mask${defGuid})` : undefined, opacity: 1.0, // opacity: strokeWidth !== width ? 0.5 : undefined, pointerEvents: pevents as any, diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index d7e8b1c05..8291ff3f1 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -27,7 +27,7 @@ import { Doc, HeightSym, WidthSym } from '../../fields/Doc'; import { InkData, InkField } from '../../fields/InkField'; import { BoolCast, Cast, NumCast, RTFCast, StrCast } from '../../fields/Types'; import { TraceMobx } from '../../fields/util'; -import { OmitKeys, returnFalse, setupMoveUpEvents } from '../../Utils'; +import { DashColor, OmitKeys, returnFalse, setupMoveUpEvents } from '../../Utils'; import { CognitiveServices } from '../cognitive_services/CognitiveServices'; import { InteractionUtils } from '../util/InteractionUtils'; import { SnappingManager } from '../util/SnappingManager'; @@ -355,7 +355,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { const markerScale = NumCast(this.layoutDoc.strokeMarkerScale, 1); const closed = InkingStroke.IsClosed(inkData); const isInkMask = BoolCast(this.layoutDoc.isInkMask); - const fillColor = isInkMask ? Colors.WHITE : StrCast(this.layoutDoc.fillColor, 'transparent'); + const fillColor = isInkMask ? DashColor(StrCast(this.layoutDoc.fillColor, 'transparent')).blacken(0).rgb().toString() : StrCast(this.layoutDoc.fillColor, 'transparent'); const strokeColor = !closed && fillColor && fillColor !== 'transparent' ? fillColor : this.props.styleProvider?.(this.layoutDoc, this.props, StyleProp.Color) ?? StrCast(this.layoutDoc.color); // bcz: Hack!! Not really sure why, but having fractional values for width/height of mask ink strokes causes the dragging clone (see DragManager) to be offset from where it should be. @@ -393,7 +393,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { const highlightIndex = highlight?.highlightIndex; const highlightColor = highlight?.highlightIndex ? highlight?.highlightColor : StrCast(this.layoutDoc.strokeOutlineColor, !closed && fillColor && fillColor !== 'transparent' ? StrCast(this.layoutDoc.color, 'transparent') : 'transparent'); // Invisible polygonal line that enables the ink to be selected by the user. - const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, suppressFill: boolean = false) => + const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, suppressFill: boolean = false, mask: boolean = false) => InteractionUtils.CreatePolyline( inkData, inkLeft, @@ -404,7 +404,7 @@ export class InkingStroke extends ViewBoxBaseComponent() { StrCast(this.layoutDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), StrCast(this.layoutDoc.strokeBezier), - !closed ? 'none' : fillColor === 'transparent' || suppressFill ? 'none' : fillColor, + !closed ? 'none' : !isInkMask && (fillColor === 'transparent' || suppressFill) ? 'none' : fillColor, '', '', markerScale, @@ -415,7 +415,8 @@ export class InkingStroke extends ViewBoxBaseComponent() { this.props.pointerEvents?.() ?? (this.rootDoc._lockedPosition ? 'none' : 'visiblepainted'), 0.0, false, - downHdlr + downHdlr, + mask ); const fsize = +StrCast(this.props.Document.fontSize, '12px').replace('px', ''); // bootsrap 3 style sheet sets line height to be 20px for default 14 point font size. @@ -443,8 +444,8 @@ export class InkingStroke extends ViewBoxBaseComponent() { cursor: this.props.isSelected() ? 'default' : undefined, }} {...interactions}> - {clickableLine(this.onPointerDown)} - {inkLine} + {clickableLine(this.onPointerDown, undefined, isInkMask)} + {isInkMask ? null : inkLine} {!closed || (!RTFCast(this.rootDoc.text)?.Text && (!this.props.isSelected() || Doc.UserDoc().activeInkHideTextLabels)) ? null : (