From 661c1367d27fa23c3aeb62369e92cd36eb5edabd Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Sat, 21 Oct 2023 00:41:23 -0400
Subject: change to doc decorations to be more "lightweight". made linkBox
 render links in a freeform view as a DocView.  added an auto-reset view
 option for freeforms.  fixed highlighting ink strokes.  Made groups behave
 better for selecting things 'inside' the group bounding box that aren't in
 the group.   Added vertically centered text option.

---
 src/client/views/InkingStroke.tsx | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

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

diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 9b52f5870..d619f5123 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -372,6 +372,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
     }
     render() {
         TraceMobx();
+        if (!this.rootDoc._layout_isSvg) setTimeout(action(() => (this.rootDoc._layout_isSvg = true)));
         const { inkData, inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY, inkWidth, inkHeight } = this.inkScaledData();
 
         const startMarker = StrCast(this.layoutDoc.stroke_startMarker);
@@ -390,7 +391,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
         }
         const highlight = !this.controlUndo && this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.Highlighting);
         const highlightIndex = highlight?.highlightIndex;
-        const highlightColor = (!this.props.isSelected() || !isInkMask) && highlight?.highlightIndex ? highlight?.highlightColor : undefined;
+        const highlightColor = !this.props.isSelected() && !isInkMask && highlight?.highlightIndex ? highlight?.highlightColor : undefined;
         const color = StrCast(this.layoutDoc.stroke_outlineColor, !closed && fillColor && fillColor !== 'transparent' ? StrCast(this.layoutDoc.color, 'transparent') : 'transparent');
 
         // Visually renders the polygonal line made by the user.
@@ -419,15 +420,16 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
             undefined,
             color === 'transparent' ? highlightColor : undefined
         );
+        const higlightMargin = Math.min(12, Math.max(2, 0.3 * inkStrokeWidth));
         // Invisible polygonal line that enables the ink to be selected by the user.
         const clickableLine = (downHdlr?: (e: React.PointerEvent) => void, mask: boolean = false) =>
             InteractionUtils.CreatePolyline(
                 inkData,
                 inkLeft,
                 inkTop,
-                mask && color === 'transparent' ? this.strokeColor : color,
+                mask && color === 'transparent' ? this.strokeColor : highlightColor ?? color,
                 inkStrokeWidth,
-                inkStrokeWidth + NumCast(this.layoutDoc.stroke_borderWidth) + (fillColor ? (closed ? 2 : (highlightIndex ?? 0) + 2) : 2),
+                inkStrokeWidth + NumCast(this.layoutDoc.stroke_borderWidth) + (fillColor ? (closed ? higlightMargin : (highlightIndex ?? 0) + higlightMargin) : higlightMargin),
                 StrCast(this.layoutDoc.stroke_lineJoin),
                 StrCast(this.layoutDoc.stroke_lineCap),
                 StrCast(this.layoutDoc.stroke_bezier),
-- 
cgit v1.2.3-70-g09d2


From a091c6142db5c1da94807abf14e78ed69e62f794 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 31 Oct 2023 12:21:30 -0400
Subject: fixed groups to use actual document boundaries for ink or link lines,
 instead of boundingbox.  fixed doc title css.  started to make link lines
 more compatible with ink.

---
 src/client/util/InteractionUtils.tsx                  |  6 +++---
 src/client/views/DocumentDecorations.tsx              | 11 ++++-------
 src/client/views/EditableView.tsx                     |  2 ++
 src/client/views/InkingStroke.tsx                     |  1 -
 src/client/views/PropertiesButtons.tsx                |  2 +-
 src/client/views/PropertiesView.tsx                   |  7 +------
 src/client/views/StyleProvider.scss                   |  2 +-
 src/client/views/StyleProvider.tsx                    | 19 ++++++++++---------
 .../collectionFreeForm/CollectionFreeFormView.tsx     |  5 +----
 .../views/nodes/CollectionFreeFormDocumentView.tsx    | 17 +++++++++++++----
 src/client/views/nodes/DocumentView.tsx               | 17 +++++++++--------
 src/client/views/nodes/LinkBox.tsx                    | 12 ++++++++++--
 src/client/views/nodes/trails/PresBox.tsx             |  2 +-
 src/client/views/pdf/PDFViewer.tsx                    |  2 +-
 14 files changed, 57 insertions(+), 48 deletions(-)

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

diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index 7caeee588..be885312d 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -94,7 +94,7 @@ export namespace InteractionUtils {
         width: number,
         strokeWidth: number,
         lineJoin: string,
-        lineCap: string,
+        strokeLineCap: string,
         bezier: string,
         fill: string,
         arrowStart: string,
@@ -181,8 +181,8 @@ export namespace InteractionUtils {
                         // opacity: strokeWidth !== width ? 0.5 : undefined,
                         pointerEvents: (pevents as any) === 'all' ? 'visiblepainted' : (pevents as any),
                         stroke: color ?? 'rgb(0, 0, 0)',
-                        strokeWidth: strokeWidth,
-                        strokeLinecap: lineCap as any,
+                        strokeWidth,
+                        strokeLinecap: strokeLineCap as any,
                         strokeDasharray: dashArray,
                         transition: 'inherit',
                     }}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 9dafb12fb..65f7c7a70 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -475,6 +475,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
 
     @action
     onPointerDown = (e: React.PointerEvent): void => {
+        this._isResizing = true;
         setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction);
         DocumentView.Interacting = true; // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them
         this._resizeHdlId = e.currentTarget.className;
@@ -685,6 +686,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
 
     @action
     onPointerUp = (e: PointerEvent): void => {
+        this._isResizing = false;
         this._resizeHdlId = '';
         DocumentView.Interacting = false;
         this._resizeUndo?.end();
@@ -772,7 +774,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
         var shareSymbolIcon = ReverseHierarchyMap.get(shareMode)?.image;
 
         // hide the decorations if the parent chooses to hide it or if the document itself hides it
-        const hideDecorations = seldocview.props.hideDecorations || seldocview.rootDoc.hideDecorations;
+        const hideDecorations = this._isResizing || seldocview.props.hideDecorations || seldocview.rootDoc.layout_hideDecorations;
         const hideResizers =
             ![AclAdmin, AclEdit, AclAugment].includes(GetEffectiveAcl(seldocview.rootDoc)) || hideDecorations || seldocview.props.hideResizeHandles || seldocview.rootDoc.layout_hideResizeHandles || this._isRounding || this._isRotating;
         const hideTitle = this._showNothing || hideDecorations || seldocview.props.hideDecorationTitle || seldocview.rootDoc.layout_hideDecorationTitle || this._isRounding || this._isRotating;
@@ -861,12 +863,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
                 onPointerDown={e => e.stopPropagation()}
             />
         ) : (
-            <div
-                className="documentDecorations-title"
-                key="title"
-                onPointerDown={e => {
-                    e.stopPropagation;
-                }}>
+            <div className="documentDecorations-title" key="title" onPointerDown={e => e.stopPropagation}>
                 {hideTitle ? null : (
                     <span className="documentDecorations-titleSpan" onPointerDown={this.onTitleDown}>
                         {this.selectionTitle}
diff --git a/src/client/views/EditableView.tsx b/src/client/views/EditableView.tsx
index ed7c544fc..abb7ed7ee 100644
--- a/src/client/views/EditableView.tsx
+++ b/src/client/views/EditableView.tsx
@@ -290,6 +290,8 @@ export class EditableView extends React.Component<EditableProps> {
                     whiteSpace: this.props.oneLine ? 'nowrap' : 'pre-line',
                     height: this.props.height,
                     maxHeight: this.props.maxHeight,
+                    fontStyle: this.props.fontStyle,
+                    fontSize: this.props.fontSize,
                 }}
                 //onPointerDown={this.stopPropagation}
                 onClick={this.onClick}
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index d619f5123..c3a6b1607 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -372,7 +372,6 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
     }
     render() {
         TraceMobx();
-        if (!this.rootDoc._layout_isSvg) setTimeout(action(() => (this.rootDoc._layout_isSvg = true)));
         const { inkData, inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY, inkWidth, inkHeight } = this.inkScaledData();
 
         const startMarker = StrCast(this.layoutDoc.stroke_startMarker);
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index ff79a8390..18f53b8e7 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -492,7 +492,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     render() {
         const layoutField = this.selectedDoc?.[Doc.LayoutFieldKey(this.selectedDoc)];
         const isText = layoutField instanceof RichTextField;
-        const isInk = layoutField instanceof InkField;
+        const isInk = this.selectedDoc?.layout_isSvg;
         const isImage = layoutField instanceof ImageField;
         const isMap = this.selectedDoc?.type === DocumentType.MAP;
         const isCollection = this.selectedDoc?.type === DocumentType.COL;
diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 04a948a27..d37971517 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -73,9 +73,6 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     @computed get isPres(): boolean {
         return this.selectedDoc?.type === DocumentType.PRES;
     }
-    @computed get isLink(): boolean {
-        return this.selectedDoc?.type === DocumentType.LINK;
-    }
     @computed get dataDoc() {
         return this.selectedDoc?.[DocData];
     }
@@ -1174,12 +1171,10 @@ export class PropertiesView extends React.Component<PropertiesViewProps> {
     }
 
     @computed get inkSubMenu() {
-        let isDouble = false;
-
         return (
             <>
                 <PropertiesSection title="Appearance" isOpen={this.openAppearance} setIsOpen={bool => (this.openAppearance = bool)} onDoubleClick={() => this.CloseAll()}>
-                    {this.isInk ? this.appearanceEditor : null}
+                    {this.selectedDoc?.layout_isSvg ? this.appearanceEditor : null}
                 </PropertiesSection>
                 <PropertiesSection title="Transform" isOpen={this.openTransform} setIsOpen={bool => (this.openTransform = bool)} onDoubleClick={() => this.CloseAll()}>
                     {this.transformEditor}
diff --git a/src/client/views/StyleProvider.scss b/src/client/views/StyleProvider.scss
index f069e7e1b..4d3096f71 100644
--- a/src/client/views/StyleProvider.scss
+++ b/src/client/views/StyleProvider.scss
@@ -12,7 +12,7 @@
     opacity: 0.3;
     display: flex;
     flex-direction: column;
-    color: gold;
+    color: red;
     border-radius: 3px;
     justify-content: center;
     cursor: default;
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 5ff743a30..c6d3efd0c 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -83,8 +83,9 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
     const selected = property.includes(':selected');
     const isCaption = property.includes(':caption');
     const isAnchor = property.includes(':anchor');
+    const isContent = property.includes(':content');
     const isAnnotated = property.includes(':annotated');
-    const isInk = () => doc && doc._layout_isSvg && !props?.LayoutTemplateString;
+    const isInk = () => doc?._layout_isSvg && !props?.LayoutTemplateString;
     const isOpen = property.includes(':open');
     const isEmpty = property.includes(':empty');
     const boxBackground = property.includes(':box');
@@ -121,14 +122,14 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 const highlightStyle = ['solid', 'dashed', 'solid', 'solid', 'solid'][highlightIndex];
                 if (highlightIndex) {
                     return {
-                        highlightStyle,
+                        highlightStyle: doc._isGroup ? "dotted": highlightStyle,
                         highlightColor,
                         highlightIndex,
-                        highlightStroke: doc.type === DocumentType.INK || doc.type === DocumentType.LINK,
+                        highlightStroke: doc.layout_isSvg,
                     };
                 }
             }
-            return undefined;
+            return  undefined;
         case StyleProp.DocContents:return undefined;
         case StyleProp.WidgetColor:return isAnnotated ? Colors.LIGHT_BLUE : 'dimgrey';
         case StyleProp.Opacity:    return props?.LayoutTemplateString?.includes(KeyValueBox.name) ? 1 : doc?.text_inlineAnnotations ? 0 :  Cast(doc?._opacity, "number", Cast(doc?.opacity, 'number', null));
@@ -171,7 +172,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         case StyleProp.BorderPath:
             const borderPath = Doc.IsComicStyle(doc) &&
                 props?.renderDepth &&
-                ![DocumentType.INK, DocumentType.LINK].includes(doc?.type as any) && { path: wavyBorderPath(props?.PanelWidth?.() || 0, props?.PanelHeight?.() || 0), fill: wavyBorderPath(props?.PanelWidth?.() || 0, props?.PanelHeight?.() || 0, 0.08), width: 3 };
+                !doc?.layout_isSvg && { path: wavyBorderPath(props?.PanelWidth?.() || 0, props?.PanelHeight?.() || 0), fill: wavyBorderPath(props?.PanelWidth?.() || 0, props?.PanelHeight?.() || 0, 0.08), width: 3 };
             return !borderPath
                 ? null
                 : {
@@ -231,7 +232,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         case StyleProp.BoxShadow: {
             if (!doc || opacity() === 0 || doc.noShadow) return undefined; // if it's not visible, then no shadow)
             if (doc.layout_boxShadow === 'standard') return Shadows.STANDARD_SHADOW;
-            if (IsFollowLinkScript(doc?.onClick) && LinkManager.Links(doc).length && ![DocumentType.LINK, DocumentType.INK].includes(doc.type as any)) return StrCast(doc?._linkButtonShadow, 'lightblue 0em 0em 1em');
+            if (IsFollowLinkScript(doc?.onClick) && LinkManager.Links(doc).length && !doc.layout_isSvg) return StrCast(doc?._linkButtonShadow, 'lightblue 0em 0em 1em');
             switch (doc?.type) {
                 case DocumentType.COL:
                     return StrCast(
@@ -240,7 +241,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                             ? '4px 4px 10px 2px'
                             : lockedPosition() || doc?._isGroup || docProps?.LayoutTemplateString
                             ? undefined // groups have no drop shadow -- they're supposed to be "invisible".  LayoutString's imply collection is being rendered as something else (e.g., title of a Slide)
-                            : `${Colors.MEDIUM_GRAY} ${StrCast(doc.layout_boxShadow, '0.2vw 0.2vw 0.8vw')}`
+                            : `${Colors.DARK_GRAY} ${StrCast(doc.layout_boxShadow, '0.2vw 0.2vw 0.8vw')}`
                     );
 
                 case DocumentType.LABEL:
@@ -258,12 +259,12 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
             }
         }
         case StyleProp.PointerEvents:
-            if (!props?.treeViewDoc && doc?._isGroup && (!doc.backgroundColor || doc.backgroundColor === 'transparent') && !props?.DocumentView?.().docView?.isContentActive?.()) return 'none'; // groups with no backgrounds that are not active (eg selected, or child selected), don't directly respond to pointer events (but their children can to allow the group to be selected or dragged)
             if (StrCast(doc?.pointerEvents) && !props?.LayoutTemplateString?.includes(KeyValueBox.name)) return StrCast(doc!.pointerEvents); // honor pointerEvents field (set by lock button usually) if it's not a keyValue view of the Doc
             if (docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.() !== undefined) return docProps?.DocumentView?.().ComponentView?.overridePointerEvents?.();
             if (DocumentView.ExploreMode || doc?.layout_unrendered) return isInk() ? 'visiblePainted' : 'all';
             if (props?.pointerEvents?.() === 'none') return 'none';
             if (opacity() === 0) return 'none';
+            if (props?.isGroupActive?.() ) return isInk()  ? 'visiblePainted':  (doc?._isGroup )? undefined: 'all' 
             if (props?.isDocumentActive?.() && !props.treeViewDoc) return isInk() ? 'visiblePainted' : 'all';
             return undefined; // fixes problem with tree view elements getting pointer events when the tree view is not active
         case StyleProp.Decorations:
@@ -271,7 +272,7 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
                 if (props?.docViewPath().lastElement()?.rootDoc?._type_collection === CollectionViewType.Freeform) {
                     return doc?.pointerEvents !== 'none' ? null : (
                         <div className="styleProvider-lock" onClick={() => toggleLockedPosition(doc)}>
-                            <FontAwesomeIcon icon='lock' style={{ color: 'red' }} size="lg" />
+                            <FontAwesomeIcon icon='lock' size="lg" />
                         </div>
                     );
                 }
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 9639ec73c..0d43d6ab8 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1300,16 +1300,15 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
     }
     childPointerEventsFunc = () => this.childPointerEvents;
     childContentsActive = () => (this.props.childContentsActive ?? this.isContentActive() === false ? returnFalse : emptyFunction)();
-    groupChildPointerEvents = () => (this.props.isDocumentActive?.() && !this.isContentActive() ? 'all' : 'none');
     getChildDocView(entry: PoolData) {
         const childLayout = entry.pair.layout;
         const childData = entry.pair.data;
         return (
             <CollectionFreeFormDocumentView
                 key={childLayout[Id] + (entry.replica || '')}
-                GroupPointerEvents={this.rootDoc._isGroup ? this.groupChildPointerEvents : (childLayout._isGroup && !this.childContentsActive()) || childLayout.pointerEvents === 'none' ? returnNone : undefined}
                 DataDoc={childData}
                 Document={childLayout}
+                isGroupActive={this.props.isGroupActive}
                 renderDepth={this.props.renderDepth + 1}
                 replica={entry.replica}
                 hideDecorations={BoolCast(childLayout._layout_isSvg && childLayout.type === DocumentType.LINK)}
@@ -1831,8 +1830,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
 
         this.props.Document._isGroup && this.Document.transcription && appearanceItems.push({ description: 'Ink to text', event: () => this.transcribeStrokes(false), icon: 'font' });
 
-        // this.props.Document._isGroup && this.childDocs.filter(s => s.type === DocumentType.INK).length > 0 && appearanceItems.push({ description: "Ink to math", event: () => this.transcribeStrokes(true), icon: "square-root-alt" });
-
         !Doc.noviceMode ? appearanceItems.push({ description: 'Arrange contents in grid', event: this.layoutDocsInGrid, icon: 'table' }) : null;
         !appearance && ContextMenu.Instance.addItem({ description: 'Appearance...', subitems: appearanceItems, icon: 'eye' });
 
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 199835dd9..9f7ebc5d9 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -25,7 +25,6 @@ export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps {
     dataTransition?: string;
     replica: string;
     CollectionFreeFormView: CollectionFreeFormView;
-    GroupPointerEvents?: () => 'none' | 'all' | undefined; // pointer events for this freeform doc view wrapper that are not passed to the docView.  This allows items in a group to trigger the group to be selected, without selecting the items themselves
 }
 
 @observer
@@ -192,17 +191,27 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     screenToLocalTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.X, -this.Y);
     returnThis = () => this;
 
+    /// this indicates whether the doc view is activated because of its relationshop to a group
+    //  'group' - this is a group that is activated because it's on an active canvas, but is not part of some other group
+    //  'child' - this is a group child that is activated because its containing group is activated
+    //  'inactive' - this is a group child but it is not active
+    //  undefined - this is not activated by a group
+    isGroupActive = () => {
+        if (this.props.CollectionFreeFormView.isAnyChildContentActive()) return undefined;
+        const isGroup = this.rootDoc._isGroup && (!this.rootDoc.backgroundColor || this.rootDoc.backgroundColor === 'transparent');
+        return isGroup ? (this.props.isDocumentActive?.() ? 'group' : this.props.isGroupActive?.() ? 'child' : 'inactive') : this.props.isGroupActive?.() ? 'child' : undefined;
+    };
     render() {
         TraceMobx();
         const divProps: DocumentViewProps = {
-            ...OmitKeys(this.props, ['GroupPointerEvents']).omit,
+            ...this.props,
             CollectionFreeFormDocumentView: this.returnThis,
             styleProvider: this.styleProvider,
             ScreenToLocalTransform: this.screenToLocalTransform,
             PanelWidth: this.panelWidth,
             PanelHeight: this.panelHeight,
+            isGroupActive: this.isGroupActive,
         };
-        const isInk = this.layoutDoc._layout_isSvg && !this.props.LayoutTemplateString && !this.layoutDoc._stroke_isInkMask;
         return (
             <div
                 className="collectionFreeFormDocumentView-container"
@@ -214,7 +223,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                     transition: this.dataProvider?.transition ?? (this.props.dataTransition ? this.props.dataTransition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.dataTransition)),
                     zIndex: this.ZInd,
                     display: this.sizeProvider?.width ? undefined : 'none',
-                    pointerEvents: this.props.GroupPointerEvents?.() ?? (isInk ? 'none' : undefined),
+                    pointerEvents: 'none',
                 }}>
                 {this.props.renderCutoffProvider(this.props.Document) ? (
                     <div style={{ position: 'absolute', width: this.panelWidth(), height: this.panelHeight(), background: 'lightGreen' }} />
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 43be4b724..a2a084200 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1,5 +1,6 @@
 import { IconProp } from '@fortawesome/fontawesome-svg-core';
-import { action, computed, IReactionDisposer, observable, reaction, runInAction, trace } from 'mobx';
+import { Dropdown, DropdownType, Type } from 'browndash-components';
+import { action, computed, IReactionDisposer, observable, reaction, runInAction } from 'mobx';
 import { observer } from 'mobx-react';
 import { computedFn } from 'mobx-utils';
 import { Bounce, Fade, Flip, LightSpeed, Roll, Rotate, Zoom } from 'react-reveal';
@@ -38,7 +39,6 @@ import { ContextMenuProps } from '../ContextMenuItem';
 import { DocComponent } from '../DocComponent';
 import { EditableView } from '../EditableView';
 import { GestureOverlay } from '../GestureOverlay';
-import { InkingStroke } from '../InkingStroke';
 import { LightboxView } from '../LightboxView';
 import { StyleProp } from '../StyleProvider';
 import { UndoStack } from '../UndoStack';
@@ -48,14 +48,11 @@ import { DocumentLinksButton } from './DocumentLinksButton';
 import './DocumentView.scss';
 import { FieldViewProps } from './FieldView';
 import { FormattedTextBox } from './formattedText/FormattedTextBox';
+import { KeyValueBox } from './KeyValueBox';
 import { LinkAnchorBox } from './LinkAnchorBox';
 import { PresEffect, PresEffectDirection } from './trails';
 import { PinProps, PresBox } from './trails/PresBox';
 import React = require('react');
-import { KeyValueBox } from './KeyValueBox';
-import { LinkBox } from './LinkBox';
-import { FilterPanel } from '../FilterPanel';
-import { Dropdown, DropdownType, Type } from 'browndash-components';
 const { Howl } = require('howler');
 
 interface Window {
@@ -159,6 +156,7 @@ export interface DocumentViewSharedProps {
     Document: Doc;
     DataDoc?: Doc;
     fitContentsToBox?: () => boolean; // used by freeformview to fit its contents to its panel. corresponds to _freeform_fitContentsToBox property on a Document
+    isGroupActive?: () => string | undefined; // is this document part of a group that is active
     suppressSetHeight?: boolean;
     setContentView?: (view: DocComponentView) => any;
     CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView;
@@ -428,6 +426,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     public static addDocTabFunc: (doc: Doc, location: OpenWhere) => boolean = returnFalse;
 
     onClick = action((e: React.MouseEvent | React.PointerEvent) => {
+        if (this.props.isGroupActive?.() === 'child' && !this.props.isDocumentActive?.()) return;
         if (!this.Document.ignoreClick && this.props.renderDepth >= 0 && Utils.isClick(e.clientX, e.clientY, this._downX, this._downY, this._downTime)) {
             let stopPropagate = true;
             let preventDefault = true;
@@ -516,6 +515,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
     @action
     onPointerDown = (e: React.PointerEvent): void => {
+        if (this.props.isGroupActive?.() === 'child' && !this.props.isDocumentActive?.()) return;
         this._longPressSelector = setTimeout(() => {
             if (DocumentView.LongPress) {
                 if (this.rootDoc.undoIgnoreFields) {
@@ -906,11 +906,12 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     @computed get contents() {
         TraceMobx();
         const isInk = this.layoutDoc._layout_isSvg && !this.props.LayoutTemplateString;
+        const noBackground = this.rootDoc._isGroup && (!this.rootDoc.backgroundColor || this.rootDoc.backgroundColor === 'transparent');
         return (
             <div
                 className="documentView-contentsView"
                 style={{
-                    pointerEvents: (isInk ? 'none' : this.contentPointerEvents()) ?? 'all',
+                    pointerEvents: (isInk || noBackground ? 'none' : this.contentPointerEvents()) ?? 'all',
                     height: this.headerMargin ? `calc(100% - ${this.headerMargin}px)` : undefined,
                 }}>
                 <DocumentContentsView
@@ -1309,7 +1310,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 onPointerLeave={e => !isParentOf(this.ContentDiv, document.elementFromPoint(e.nativeEvent.x, e.nativeEvent.y)) && Doc.UnBrushDoc(this.rootDoc)}
                 style={{
                     borderRadius: this.borderRounding,
-                    pointerEvents: this.pointerEvents === 'visiblePainted' ? 'none' : this.pointerEvents,
+                    pointerEvents: this.pointerEvents === 'visiblePainted' ? 'none' : this.pointerEvents, // visible painted means that the underlying doc contents are irregular and will process their own pointer events (otherwise, the contents are expected to fill the entire doc view box so we can handle pointer events here)
                 }}>
                 <>
                     {this._componentView instanceof KeyValueBox ? renderDoc : DocumentViewInternal.AnimationEffect(renderDoc, this.rootDoc[Animation], this.rootDoc)}
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index d871c88ba..682267ef1 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -4,7 +4,7 @@ import { computed, action } from 'mobx';
 import { observer } from 'mobx-react';
 import { Height, Width } from '../../../fields/DocSymbols';
 import { Id } from '../../../fields/FieldSymbols';
-import { DocCast, StrCast } from '../../../fields/Types';
+import { DocCast, NumCast, StrCast } from '../../../fields/Types';
 import { aggregateBounds, emptyFunction, returnAlways, returnFalse, Utils } from '../../../Utils';
 import { DocumentManager } from '../../util/DocumentManager';
 import { ViewBoxBaseComponent } from '../DocComponent';
@@ -92,6 +92,9 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
             const bez = new Bezier(pts.map(p => ({ x: p[0], y: p[1] })));
             const text = bez.get(0.5);
             const linkDesc = StrCast(this.rootDoc.link_description) || 'description';
+            const strokeWidth = NumCast(this.rootDoc.stroke_width, 4);
+            const dash = StrCast(this.rootDoc.stroke_dash);
+            const strokeDasharray = dash && Number(dash) ? String(strokeWidth * Number(dash)) : undefined;
             return (
                 <div style={{ pointerEvents: 'none', position: 'absolute', width: '100%', height: '100%' }}>
                     <svg width={Math.max(100, rx - lx)} height={Math.max(100, by - ty)} style={{ overflow: 'visible' }}>
@@ -106,7 +109,12 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
                         </defs>
                         <path
                             className="collectionfreeformlinkview-linkLine"
-                            style={{ pointerEvents: this.props.pointerEvents?.() === 'none' ? 'none' : 'visibleStroke', stroke: highlightColor ?? 'lightblue', strokeWidth: 4 }}
+                            style={{
+                                pointerEvents: this.props.pointerEvents?.() === 'none' ? 'none' : 'visibleStroke', //
+                                stroke: highlightColor ?? 'lightblue',
+                                strokeDasharray,
+                                strokeWidth,
+                            }}
                             d={`M ${pts[1][0] - lx} ${pts[1][1] - ty} C ${pts[1][0] + pts[1][0] - pts[0][0] - lx} ${pts[1][1] + pts[1][1] - pts[0][1] - ty}, 
                             ${pts[2][0] + pts[2][0] - pts[3][0] - lx} ${pts[2][1] + pts[2][1] - pts[3][1] - ty}, ${pts[2][0] - lx} ${pts[2][1] - ty}`}
                         />
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index ceeb10d93..70d9443a2 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -792,7 +792,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
             willPan: activeItem.presentation_movement !== PresMovement.None,
             willZoomCentered: activeItem.presentation_movement === PresMovement.Zoom || activeItem.presentation_movement === PresMovement.Jump || activeItem.presentation_movement === PresMovement.Center,
             zoomScale: activeItem.presentation_movement === PresMovement.Center ? 0 : NumCast(activeItem.config_zoom, 1),
-            zoomTime: activeItem.presentation_movement === PresMovement.Jump ? 0 : Math.min(Math.max(effect ? 750 : 500, (effect ? 1 : 1) * presTime), presTime),
+            zoomTime: activeItem.presentation_movement === PresMovement.Jump ? 0 : Math.min(Math.max(effect ? 750 : 500, (effect ? 0.2 : 1) * presTime), presTime),
             effect: activeItem,
             noSelect: true,
             openLocation: OpenWhere.addLeft,
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 58a54764d..939928c1c 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -519,7 +519,7 @@ export class PDFViewer extends React.Component<IViewerProps> {
     childStyleProvider = (doc: Doc | undefined, props: Opt<DocumentViewProps>, property: string): any => {
         if (doc instanceof Doc && property === StyleProp.PointerEvents) {
             if (this.inlineTextAnnotations.includes(doc) || this.props.isContentActive() === false) return 'none';
-            const isInk = doc && StrCast(Doc.Layout(doc).layout).includes(InkingStroke.name) && !props?.LayoutTemplateString;
+            const isInk = doc.layout_isSvg && !props?.LayoutTemplateString;
             return isInk ? 'visiblePainted' : 'all';
         }
         return this.props.styleProvider?.(doc, props, property);
-- 
cgit v1.2.3-70-g09d2


From cf95923feebb274249283c7bb82de5849060a9a8 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Tue, 31 Oct 2023 14:21:51 -0400
Subject: fixed keyframe animation of ink and links.  fixed getDocumentview
 with preferred collection

---
 src/client/documents/Documents.ts       | 26 ++++++++++++--------------
 src/client/util/DocumentManager.ts      | 18 +++++-------------
 src/client/views/InkStrokeProperties.ts |  2 +-
 src/client/views/InkingStroke.tsx       |  2 +-
 src/client/views/nodes/LinkBox.tsx      |  9 +++++----
 5 files changed, 24 insertions(+), 33 deletions(-)

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

diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 5c913513a..4086ede20 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -670,7 +670,15 @@ export namespace Docs {
                 {
                     // NOTE: this is unused!! ink fields are filled in directly within the InkDocument() method
                     layout: { view: InkingStroke, dataField: 'stroke' },
-                    options: { systemIcon: 'BsFillPencilFill', nativeDimModifiable: true, nativeHeightUnfrozen: true, layout_isSvg: true, layout_forceReflow: true },
+                    options: {
+                        systemIcon: 'BsFillPencilFill', //
+                        nativeDimModifiable: true,
+                        nativeHeightUnfrozen: true,
+                        layout_hideDecorationTitle: true, // don't show title when selected
+                        fitWidth: false,
+                        layout_isSvg: true,
+                        layout_forceReflow: true,
+                    },
                 },
             ],
             [
@@ -1035,16 +1043,8 @@ export namespace Docs {
         }
 
         export function InkDocument(color: string, strokeWidth: number, stroke_bezier: string, fillColor: string, arrowStart: string, arrowEnd: string, dash: string, points: PointData[], isInkMask: boolean, options: DocumentOptions = {}) {
-            const I = new Doc();
-            I[Initializing] = true;
-            I.type = DocumentType.INK;
-            I.layout = InkingStroke.LayoutString('stroke');
-            I.nativeDimModifiable = true;
-            I.nativeHeightUnfrozen = true;
-            I.layout_isSvg = true;
-            I.layout_forceReflow = true;
-            I.layout_fitWidth = false;
-            I.layout_hideDecorationTitle = true; // don't show title when selected
+            const ink = InstanceFromProto(Prototypes.get(DocumentType.INK), '', { title: 'ink', ...options });
+            const I = Doc.GetProto(ink);
             // I.layout_hideOpenButton = true; // don't show open full screen button when selected
             I.color = color;
             I.fillColor = fillColor;
@@ -1056,8 +1056,6 @@ export namespace Docs {
             I.stroke_dash = dash;
             I.stroke_isInkMask = isInkMask;
             I.text_align = 'center';
-            I.title = 'ink';
-            I.author = Doc.CurrentUserEmail;
             I.rotation = 0;
             I.defaultDoubleClick = 'click';
             I.author_date = new DateField();
@@ -1065,7 +1063,7 @@ export namespace Docs {
             //I['acl-Override'] = SharingPermissions.Unset;
             I[Initializing] = false;
 
-            return InstanceFromProto(I, '', options);
+            return ink;
         }
 
         export function PdfDocument(url: string, options: DocumentOptions = {}, overwriteDoc?: Doc) {
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index b9f6059f4..f7eca2379 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -146,22 +146,14 @@ export class DocumentManager {
         return this.getDocumentViewsById(doc[Id]);
     }
 
-    public getDocumentView(toFind: Doc | undefined, preferredCollection?: DocumentView): DocumentView | undefined {
-        const doc =
-            // bcz: this was temporary code used to match documents by data url instead of by id. intended only for repairing the DB
-            // Array.from(DocumentManager.Instance.DocumentViews).find(
-            //     dv =>
-            //         ((dv.rootDoc.data as any)?.url?.href && (dv.rootDoc.data as any)?.url?.href === (toFind.data as any)?.url?.href) ||
-            //         ((DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href && (DocCast(dv.rootDoc.annotationOn)?.data as any)?.url?.href === (DocCast(toFind.annotationOn)?.data as any)?.url?.href)
-            // )?.rootDoc ??
-            toFind;
+    public getDocumentView(target: Doc | undefined, preferredCollection?: DocumentView): DocumentView | undefined {
         const docViewArray = DocumentManager.Instance.DocumentViews;
-        const passes = !doc ? [] : preferredCollection ? [preferredCollection, undefined] : [undefined];
+        const passes = !target ? [] : preferredCollection ? [preferredCollection, undefined] : [undefined];
         return passes.reduce(
-            (pass, toReturn) =>
+            (toReturn, pass) =>
                 toReturn ??
-                docViewArray.filter(view => view.rootDoc === doc).find(view => !pass || view.props.docViewPath().lastElement() === preferredCollection) ??
-                docViewArray.filter(view => Doc.AreProtosEqual(view.rootDoc, doc)).find(view => !pass || view.props.docViewPath().lastElement() === preferredCollection),
+                docViewArray.filter(view => view.rootDoc === target).find(view => !pass || view.props.docViewPath().lastElement() === preferredCollection) ??
+                docViewArray.filter(view => Doc.AreProtosEqual(view.rootDoc, target)).find(view => !pass || view.props.docViewPath().lastElement() === preferredCollection),
             undefined as Opt<DocumentView>
         );
     }
diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts
index 13bd12361..736ca8d90 100644
--- a/src/client/views/InkStrokeProperties.ts
+++ b/src/client/views/InkStrokeProperties.ts
@@ -65,7 +65,7 @@ export class InkStrokeProperties {
                                 doc._height = (newYrange.max - newYrange.min) * ptsYscale + NumCast(doc.stroke_width);
                                 doc.x = oldXrange.coord + (newXrange.min - oldXrange.min) * ptsXscale;
                                 doc.y = oldYrange.coord + (newYrange.min - oldYrange.min) * ptsYscale;
-                                Doc.GetProto(doc).stroke = new InkField(newPoints);
+                                Doc.SetInPlace(doc, 'stroke', new InkField(newPoints), true);
                                 appliedFunc = true;
                             }
                         }
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index c3a6b1607..d26c7761e 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -246,7 +246,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
      * factor for converting between ink and screen space.
      */
     inkScaledData = () => {
-        const inkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
+        const inkData = Cast(this.rootDoc[this.fieldKey], InkField)?.inkData ?? [];
         const inkStrokeWidth = NumCast(this.rootDoc.stroke_width, 1);
         const inkTop = Math.min(...inkData.map(p => p.Y)) - inkStrokeWidth / 2;
         const inkBottom = Math.max(...inkData.map(p => p.Y)) + inkStrokeWidth / 2;
diff --git a/src/client/views/nodes/LinkBox.tsx b/src/client/views/nodes/LinkBox.tsx
index 682267ef1..38ff21209 100644
--- a/src/client/views/nodes/LinkBox.tsx
+++ b/src/client/views/nodes/LinkBox.tsx
@@ -28,12 +28,12 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
     @computed get anchor1() {
         const anchor1 = DocCast(this.rootDoc.link_anchor_1);
         const anchor_1 = anchor1?.layout_unrendered ? DocCast(anchor1.annotationOn) : anchor1;
-        return DocumentManager.Instance.getDocumentView(anchor_1);
+        return DocumentManager.Instance.getDocumentView(anchor_1, this.props.docViewPath()[this.props.docViewPath().length - 2]); // this.props.docViewPath().lastElement());
     }
     @computed get anchor2() {
         const anchor2 = DocCast(this.rootDoc.link_anchor_2);
         const anchor_2 = anchor2?.layout_unrendered ? DocCast(anchor2.annotationOn) : anchor2;
-        return DocumentManager.Instance.getDocumentView(anchor_2);
+        return DocumentManager.Instance.getDocumentView(anchor_2, this.props.docViewPath()[this.props.docViewPath().length - 2]); // this.props.docViewPath().lastElement());
     }
     screenBounds = () => {
         if (this.layoutDoc._layout_isSvg && this.anchor1 && this.anchor2 && this.anchor1.props.CollectionFreeFormDocumentView?.().props.CollectionFreeFormView) {
@@ -96,8 +96,8 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
             const dash = StrCast(this.rootDoc.stroke_dash);
             const strokeDasharray = dash && Number(dash) ? String(strokeWidth * Number(dash)) : undefined;
             return (
-                <div style={{ pointerEvents: 'none', position: 'absolute', width: '100%', height: '100%' }}>
-                    <svg width={Math.max(100, rx - lx)} height={Math.max(100, by - ty)} style={{ overflow: 'visible' }}>
+                <div style={{ transition: 'inherit', pointerEvents: 'none', position: 'absolute', width: '100%', height: '100%' }}>
+                    <svg width={Math.max(100, rx - lx)} height={Math.max(100, by - ty)} style={{ transition: 'inherit', overflow: 'visible' }}>
                         <defs>
                             <filter x="0" y="0" width="1" height="1" id={`${this.rootDoc[Id] + 'background'}`}>
                                 <feFlood floodColor={`${StrCast(this.rootDoc._backgroundColor, 'lightblue')}`} result="bg" />
@@ -114,6 +114,7 @@ export class LinkBox extends ViewBoxBaseComponent<FieldViewProps>() {
                                 stroke: highlightColor ?? 'lightblue',
                                 strokeDasharray,
                                 strokeWidth,
+                                transition: 'inherit',
                             }}
                             d={`M ${pts[1][0] - lx} ${pts[1][1] - ty} C ${pts[1][0] + pts[1][0] - pts[0][0] - lx} ${pts[1][1] + pts[1][1] - pts[0][1] - ty}, 
                             ${pts[2][0] + pts[2][0] - pts[3][0] - lx} ${pts[2][1] + pts[2][1] - pts[3][1] - ty}, ${pts[2][0] - lx} ${pts[2][1] - ty}`}
-- 
cgit v1.2.3-70-g09d2

