From 8beb8fa42ba5f84bb13b5877560fc92ad3613e88 Mon Sep 17 00:00:00 2001
From: mehekj <mehek.jethani@gmail.com>
Date: Wed, 25 Aug 2021 21:34:40 -0400
Subject: basic audio trim complete

---
 src/client/views/DocumentDecorations.tsx | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index d24ab974c..0424b4e63 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -389,10 +389,10 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
         this._inkDragDocs.map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] }))
             .forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => {
                 Doc.GetProto(doc).data = new InkField(inkPts.map(ipt =>  // (new x — oldx) + newWidth * (oldxpoint /oldWidth)
-                    ({
-                        X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width,
-                        Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height
-                    })));
+                ({
+                    X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width,
+                    Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height
+                })));
                 Doc.SetNativeWidth(doc, undefined);
                 Doc.SetNativeHeight(doc, undefined);
             });
@@ -402,6 +402,9 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
     get selectionTitle(): string {
         if (SelectionManager.Views().length === 1) {
             const selected = SelectionManager.Views()[0];
+            if (selected.ComponentView?.getTitle?.()) {
+                return selected.ComponentView.getTitle();
+            }
             if (this._titleControlString.startsWith("=")) {
                 return ScriptField.MakeFunction(this._titleControlString.substring(1), { doc: Doc.name })!.script.run({ self: selected.rootDoc, this: selected.layoutDoc }, console.log).result?.toString() || "";
             }
-- 
cgit v1.2.3-70-g09d2


From be825152070aa609817a2df7880e9cc377f7cfc1 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 1 Sep 2021 12:19:38 -0400
Subject: changed ctrl-click to open alias to reuse existing alias.  changed
 documentview to not clearout docView field when invalidated to allow webBox
 componentView to be persistent which allows proper settting of scrollHeight
 and allows webBox to grow to vertical space available in tab or lightbox.

---
 src/client/views/DocumentDecorations.tsx  | 17 ++++++++---------
 src/client/views/SidebarAnnos.tsx         |  3 ++-
 src/client/views/collections/TreeView.tsx |  2 +-
 src/client/views/nodes/DocumentView.tsx   |  7 ++++---
 src/client/views/nodes/WebBox.tsx         | 12 ++++++------
 src/fields/documentSchemas.ts             |  1 -
 6 files changed, 21 insertions(+), 21 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index e454be618..a570bdb34 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -3,7 +3,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { Tooltip } from '@material-ui/core';
 import { action, computed, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
-import { AclAdmin, AclEdit, DataSym, Doc, Field, HeightSym, WidthSym } from "../../fields/Doc";
+import { AclAdmin, AclEdit, DataSym, Doc, Field, HeightSym, WidthSym, DocListCast } from "../../fields/Doc";
 import { Document } from '../../fields/documentSchemas';
 import { HtmlField } from '../../fields/HtmlField';
 import { InkField } from "../../fields/InkField";
@@ -159,9 +159,8 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
         const selectedDocs = SelectionManager.Views();
         if (selectedDocs.length) {
             if (e.ctrlKey) {    // open an alias in a new tab with Ctrl Key
-                selectedDocs[0].props.Document._fullScreenView = Doc.MakeAlias(selectedDocs[0].props.Document);
-                (selectedDocs[0].props.Document._fullScreenView as Doc).context = undefined;
-                CollectionDockingView.AddSplit(selectedDocs[0].props.Document._fullScreenView as Doc, "right");
+                const bestAlias = DocListCast(selectedDocs[0].props.Document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail);
+                CollectionDockingView.AddSplit(bestAlias ?? Doc.MakeAlias(selectedDocs[0].props.Document), "right");
             } else if (e.shiftKey) {   // open centered in a new workspace with Shift Key
                 const alias = Doc.MakeAlias(selectedDocs[0].props.Document);
                 alias.context = undefined;
@@ -169,7 +168,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
                 alias.y = -alias[HeightSym]() / 2;
                 CollectionDockingView.AddSplit(Docs.Create.FreeformDocument([alias], { title: "Tab for " + alias.title }), "right");
             } else if (e.altKey) {    // open same document in new tab
-                CollectionDockingView.ToggleSplit(Cast(selectedDocs[0].props.Document._fullScreenView, Doc, null) || selectedDocs[0].props.Document, "right");
+                CollectionDockingView.ToggleSplit(selectedDocs[0].props.Document, "right");
             } else {
                 LightboxView.SetLightboxDoc(selectedDocs[0].props.Document, undefined, selectedDocs.slice(1).map(view => view.props.Document));
             }
@@ -391,10 +390,10 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
         this._inkDragDocs.map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] }))
             .forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => {
                 Doc.GetProto(doc).data = new InkField(inkPts.map(ipt =>  // (new x — oldx) + newWidth * (oldxpoint /oldWidth)
-                ({
-                    X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width,
-                    Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height
-                })));
+                    ({
+                        X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width,
+                        Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height
+                    })));
                 Doc.SetNativeWidth(doc, undefined);
                 Doc.SetNativeHeight(doc, undefined);
             });
diff --git a/src/client/views/SidebarAnnos.tsx b/src/client/views/SidebarAnnos.tsx
index 1f9763d18..0e3663f65 100644
--- a/src/client/views/SidebarAnnos.tsx
+++ b/src/client/views/SidebarAnnos.tsx
@@ -90,6 +90,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
         }
         return this.props.styleProvider?.(doc, props, property);
     }
+    setHeightCallback = (height: number) => this.props.setHeight(height + this.filtersHeight());
     render() {
         const renderTag = (tag: string) => {
             const active = StrListCast(this.props.rootDoc[this.filtersKey]).includes(`${tag}:${tag}:check`);
@@ -126,7 +127,7 @@ export class SidebarAnnos extends React.Component<FieldViewProps & ExtraProps> {
                         styleProvider={this.sidebarStyleProvider}
                         docFilters={this.docFilters}
                         scaleField={this.sidebarKey + "-scale"}
-                        setHeight={(height) => this.props.setHeight(height + this.filtersHeight())}
+                        setHeight={this.setHeightCallback}
                         isAnnotationOverlay={false}
                         select={emptyFunction}
                         scaling={returnOne}
diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx
index e8f345782..b9487054b 100644
--- a/src/client/views/collections/TreeView.tsx
+++ b/src/client/views/collections/TreeView.tsx
@@ -154,7 +154,7 @@ export class TreeView extends React.Component<TreeViewProps> {
         } else {
             // choose an appropriate alias or make one. --- choose the first alias that (1) user owns,  (2) has no context field ... otherwise make a new alias
             // this.props.addDocTab(CurrentUserUtils.ActiveDashboard.isShared ? Doc.MakeAlias(this.props.document) : this.props.document, "add:right");
-            const bestAlias = DocListCast(this.props.document.aliases).find(doc => !doc.context);
+            const bestAlias = DocListCast(this.props.document.aliases).find(doc => !doc.context && doc.author === Doc.CurrentUserEmail);
             this.props.addDocTab(bestAlias ?? Doc.MakeAlias(this.props.document), "add:right");
 
         }
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index fda84dd2d..6b9513b8b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -93,6 +93,7 @@ export interface DocComponentView {
     fieldKey?: string;
     annotationKey?: string;
     getTitle?: () => string;
+    getScrollHeight?: () => number;
 }
 export interface DocumentViewSharedProps {
     renderDepth: number;
@@ -464,7 +465,6 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 } else if (!Doc.IsSystem(this.rootDoc)) {
                     UndoManager.RunInBatch(() =>
                         LightboxView.AddDocTab(this.rootDoc, "lightbox", this.props.LayoutTemplate?.())
-                        //this.props.addDocTab((this.rootDoc._fullScreenView as Doc) || this.rootDoc, "lightbox")
                         , "double tap");
                     SelectionManager.DeselectAll();
                     Doc.UnBrushDoc(this.props.Document);
@@ -983,6 +983,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
             </div>;
     }
     render() {
+        TraceMobx();
         const highlightIndex = this.props.LayoutTemplateString ? (Doc.IsHighlighted(this.props.Document) ? 6 : 0) : Doc.isBrushedHighlightedDegree(this.props.Document); // bcz: Argh!! need to identify a tree view doc better than a LayoutTemlatString
         const highlightColor = (Doc.UserDoc().colorScheme === ColorScheme.Dark ?
             ["transparent", "#65350c", "#65350c", "yellow", "magenta", "cyan", "orange"] :
@@ -1075,7 +1076,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     @computed get panelWidth() { return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this.props.PanelWidth(); }
     @computed get panelHeight() {
         if (this.effectiveNativeHeight) {
-            return Math.min(this.props.PanelHeight(), Math.max(NumCast(this.layoutDoc.scrollHeight), this.effectiveNativeHeight) * this.nativeScaling);
+            return Math.min(this.props.PanelHeight(), Math.max(this.ComponentView?.getScrollHeight?.() ?? NumCast(this.layoutDoc.scrollHeight), this.effectiveNativeHeight) * this.nativeScaling);
         }
         return this.props.PanelHeight();
     }
@@ -1182,7 +1183,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
                         ScreenToLocalTransform={this.screenToLocalTransform}
                         focus={this.props.focus || emptyFunction}
                         bringToFront={emptyFunction}
-                        ref={action((r: DocumentViewInternal | null) => this.docView = r)} />
+                        ref={action((r: DocumentViewInternal | null) => r && (this.docView = r))} />
                 </div>)}
         </div>);
     }
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index e4d4557af..719e5a796 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -1,5 +1,5 @@
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx";
+import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, trace } from "mobx";
 import { observer } from "mobx-react";
 import * as WebRequest from 'web-request';
 import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../fields/Doc";
@@ -13,9 +13,8 @@ import { ComputedField } from "../../../fields/ScriptField";
 import { Cast, NumCast, StrCast } from "../../../fields/Types";
 import { WebField } from "../../../fields/URLField";
 import { TraceMobx } from "../../../fields/util";
-import { emptyFunction, getWordAtPoint, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, Utils, returnEmptyString, returnEmptyFilter } from "../../../Utils";
+import { emptyFunction, getWordAtPoint, OmitKeys, returnFalse, returnOne, setupMoveUpEvents, smoothScroll, Utils } from "../../../Utils";
 import { Docs } from "../../documents/Documents";
-import { DocumentType } from '../../documents/DocumentTypes';
 import { CurrentUserUtils } from "../../util/CurrentUserUtils";
 import { Scripting } from "../../util/Scripting";
 import { SnappingManager } from "../../util/SnappingManager";
@@ -59,7 +58,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
     @observable private _iframeClick: HTMLIFrameElement | undefined = undefined;
     @observable private _iframe: HTMLIFrameElement | null = null;
     @observable private _savedAnnotations = new ObservableMap<number, HTMLDivElement[]>();
-    @observable private _scrollHeight = 1500;
+    @observable private _scrollHeight = NumCast(this.layoutDoc.scrollHeight, 1500);
     @computed get _url() { return this.webField?.toString() || ""; }
     @computed get _urlHash() { return this._url ? WebBox.urlHash(this._url) + "" : ""; }
     @computed get scrollHeight() { return this._scrollHeight; }
@@ -229,6 +228,8 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         }
     }
 
+    getScrollHeight = () => this._scrollHeight;
+
     isFirefox = () => {
         return "InstallTrigger" in window; // navigator.userAgent.indexOf("Chrome") !== -1;
     }
@@ -417,8 +418,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         x !== undefined && y !== undefined && this._setPreviewCursor?.(x, y, false, false);
     }
 
-    @computed
-    get urlContent() {
+    @computed get urlContent() {
         const field = this.dataDoc[this.props.fieldKey];
         let view;
         if (field instanceof HtmlField) {
diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts
index f17a390a6..db2c6ca5b 100644
--- a/src/fields/documentSchemas.ts
+++ b/src/fields/documentSchemas.ts
@@ -15,7 +15,6 @@ export const documentSchema = createSchema({
     // "Location" properties in a very general sense
     _curPage: "number",         // current page of a page based document
     _currentFrame: "number",    // current frame of a frame based collection (e.g., a progressive slide)
-    _fullScreenView: Doc,       // alias to display when double-clicking to open document in a full-screen view
     lastFrame: "number",        // last frame of a frame based collection (e.g., a progressive slide)
     activeFrame: "number",      // the active frame of a frame based animated document 
     _currentTimecode: "number", // current play back time of a temporal document (video / audio)
-- 
cgit v1.2.3-70-g09d2


From 8cb650d9fb542465525c198c1f93f6aba7256e0b Mon Sep 17 00:00:00 2001
From: vkalev <vjk1883@gmail.com>
Date: Thu, 2 Sep 2021 12:04:02 -0400
Subject: working on moving ink UI to DocumentDecorations

---
 src/client/views/DocumentDecorations.tsx | 40 ++++++++++++++++++++++++++++----
 src/client/views/GestureOverlay.tsx      | 19 ++++++++-------
 src/client/views/InkingStroke.tsx        |  6 ++---
 src/client/views/MainView.tsx            |  3 ++-
 4 files changed, 50 insertions(+), 18 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 118d2e7c7..244d14f3a 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -28,9 +28,11 @@ import { DocumentView } from "./nodes/DocumentView";
 import React = require("react");
 import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
 import { DateField } from '../../fields/DateField';
+import { InteractionUtils } from '../util/InteractionUtils';
+import { Colors } from './global/globalEnums';
 
 @observer
-export class DocumentDecorations extends React.Component<{ boundsLeft: number, boundsTop: number }, { value: string }> {
+export class DocumentDecorations extends React.Component<{ PanelWidth: number, PanelHeight: number, boundsLeft: number, boundsTop: number }, { value: string }> {
     static Instance: DocumentDecorations;
     private _resizeHdlId = "";
     private _keyinput = React.createRef<HTMLInputElement>();
@@ -391,10 +393,10 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
         this._inkDragDocs.map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] }))
             .forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => {
                 Doc.GetProto(doc).data = new InkField(inkPts.map(ipt =>  // (new x — oldx) + newWidth * (oldxpoint /oldWidth)
-                    ({
-                        X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width,
-                        Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height
-                    })));
+                ({
+                    X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width,
+                    Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height
+                })));
                 Doc.SetNativeWidth(doc, undefined);
                 Doc.SetNativeHeight(doc, undefined);
             });
@@ -453,7 +455,34 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
         const borderRadiusDraggerWidth = 15;
         bounds.r = Math.max(bounds.x, Math.max(leftBounds, Math.min(window.innerWidth, bounds.r + borderRadiusDraggerWidth + this._resizeBorderWidth / 2) - this._resizeBorderWidth / 2 - borderRadiusDraggerWidth));
         bounds.b = Math.max(bounds.y, Math.max(topBounds, Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight));
+
         const useRotation = seldoc.rootDoc.type === DocumentType.INK;
+        const docView = SelectionManager.Views().lastElement().docView;
+        let selectedLine = null;
+
+        if (useRotation && docView) {
+            const inkData = Cast(SelectionManager.Views().lastElement().rootDoc.data, InkField)?.inkData ?? [{ X: 0, Y: 0 }];
+            const inkDoc = SelectionManager.Views().lastElement().layoutDoc;
+
+            inkData.map((point) => { docView.screenToLocal().inverse().transformPoint(point.X, point.Y); });
+
+            const strokeWidth = 4;
+            const lineTop = Math.min(...inkData.map(p => p.Y));
+            const lineBottom = Math.max(...inkData.map(p => p.Y));
+            const lineLeft = Math.min(...inkData.map(p => p.X));
+            const lineRight = Math.max(...inkData.map(p => p.X));
+            const left = lineLeft - strokeWidth / 2;
+            const top = lineTop - strokeWidth / 2;
+            const right = lineRight + strokeWidth / 2;
+            const bottom = lineBottom + strokeWidth / 2;
+            const width = Math.max(1, right - left);
+            const height = Math.max(1, bottom - top);
+            const scaleX = width === strokeWidth ? 1 : (this.props.PanelWidth - strokeWidth) / (width - strokeWidth);
+            const scaleY = height === strokeWidth ? 1 : (this.props.PanelHeight - strokeWidth) / (height - strokeWidth);
+
+            selectedLine = InteractionUtils.CreatePolyline(inkData, left, top, Colors.MEDIUM_BLUE, 4, 4, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"),
+                StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false);
+        }
 
         return (<div className="documentDecorations" style={{ background: CurrentUserUtils.ActiveDashboard?.darkScheme ? "dimgray" : "" }} >
             <div className="documentDecorations-background" style={{
@@ -473,6 +502,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
                 }}>
                     {!canDelete ? <div /> : topBtn("close", "times", undefined, this.onCloseClick, "Close")}
                     {seldoc.props.hideDecorationTitle || seldoc.props.Document.type === DocumentType.EQUATION ? (null) : titleArea}
+                    {selectedLine}
                     {seldoc.props.hideResizeHandles || seldoc.props.Document.type === DocumentType.EQUATION ? (null) :
                         <>
                             {SelectionManager.Views().length !== 1 || seldoc.Document.type === DocumentType.INK ? (null) :
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index c77521572..d0059dacc 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -688,25 +688,26 @@ export class GestureOverlay extends Touchable {
             case "rectangle":
                 this._points.push({ X: left, Y: top });
                 this._points.push({ X: left, Y: top });
-
                 this._points.push({ X: right, Y: top });
                 this._points.push({ X: right, Y: top });
+
                 this._points.push({ X: right, Y: top });
                 this._points.push({ X: right, Y: top });
-
                 this._points.push({ X: right, Y: bottom });
                 this._points.push({ X: right, Y: bottom });
+
                 this._points.push({ X: right, Y: bottom });
                 this._points.push({ X: right, Y: bottom });
-
                 this._points.push({ X: left, Y: bottom });
                 this._points.push({ X: left, Y: bottom });
+
                 this._points.push({ X: left, Y: bottom });
                 this._points.push({ X: left, Y: bottom });
-
                 this._points.push({ X: left, Y: top });
                 this._points.push({ X: left, Y: top });
+
                 break;
+                
             case "triangle":
                 this._points.push({ X: left, Y: bottom });
                 this._points.push({ X: left, Y: bottom });
@@ -736,11 +737,6 @@ export class GestureOverlay extends Touchable {
                 const radius = Math.max(centerX - Math.min(left, right), centerY - Math.min(top, bottom));
 
                 // Dividing the circle into four equal sections, and fitting each section to a cubic Bézier curve.   
-                this._points.push({ X: centerX - radius, Y: centerY });
-                this._points.push({ X: centerX - radius, Y: centerY + (c * radius) });
-                this._points.push({ X: centerX - (c * radius), Y: centerY + radius });
-                this._points.push({ X: centerX, Y: centerY + radius });
-
                 this._points.push({ X: centerX, Y: centerY + radius });
                 this._points.push({ X: centerX + (c * radius), Y: centerY + radius });
                 this._points.push({ X: centerX + radius, Y: centerY + (c * radius) });
@@ -756,6 +752,11 @@ export class GestureOverlay extends Touchable {
                 this._points.push({ X: centerX - radius, Y: centerY - (c * radius) });
                 this._points.push({ X: centerX - radius, Y: centerY });
 
+                this._points.push({ X: centerX - radius, Y: centerY });
+                this._points.push({ X: centerX - radius, Y: centerY + (c * radius) });
+                this._points.push({ X: centerX - (c * radius), Y: centerY + radius });
+                this._points.push({ X: centerX, Y: centerY + radius });
+
                 break;
 
             case "line":
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 7200d6da1..b619f858e 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -115,8 +115,8 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
         const inkLine = InteractionUtils.CreatePolyline(data, left, top, strokeColor, strokeWidth, strokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker),
             StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", 1.0, false);
         // Thin blue line indicating that the current ink stroke is selected.
-        const selectedLine = InteractionUtils.CreatePolyline(data, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth / 6, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"),
-            StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", 1.0, false);
+        // const selectedLine = InteractionUtils.CreatePolyline(data, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth / 6, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"),
+        //     StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", 1.0, false);
         // Invisible polygonal line that enables the ink to be selected by the user.
         const clickableLine = InteractionUtils.CreatePolyline(data, left, top, "transparent", strokeWidth, strokeWidth + 15, StrCast(this.layoutDoc.strokeBezier),
             StrCast(this.layoutDoc.fillColor, "none"), "none", "none", undefined, scaleX, scaleY, "", this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted", 0.0, true);
@@ -145,7 +145,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
 
                 {clickableLine}
                 {inkLine}
-                {this.props.isSelected() ? selectedLine : ""}
+                {/* {this.props.isSelected() ? selectedLine : ""} */}
                 {this.props.isSelected() && this._properties?._controlButton ?
                     <>
                         <InkControls
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index b0b8d7f41..1ce363b0a 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -65,6 +65,7 @@ import { SearchBox } from './search/SearchBox';
 import { DefaultStyleProvider, DashboardStyleProvider, StyleProp } from './StyleProvider';
 import { TopBar } from './topbar/TopBar';
 import { Colors } from './global/globalEnums';
+import { DocumentType } from '../documents/DocumentTypes';
 const _global = (window /* browser */ || global /* node */) as any;
 
 @observer
@@ -592,7 +593,7 @@ export class MainView extends React.Component {
             <CaptureManager />
             <GroupManager />
             <GoogleAuthenticationManager />
-            <DocumentDecorations boundsLeft={this.leftOffset} boundsTop={this.topOffset} />
+            <DocumentDecorations PanelWidth={this._windowWidth} PanelHeight={this._windowHeight} boundsLeft={this.leftOffset} boundsTop={this.topOffset} />
             {this.search}
             {LinkDescriptionPopup.descriptionPopup ? <LinkDescriptionPopup /> : null}
             {DocumentLinksButton.LinkEditorDocView ? <LinkMenu docView={DocumentLinksButton.LinkEditorDocView} changeFlyout={emptyFunction} /> : (null)}
-- 
cgit v1.2.3-70-g09d2


From 04920f5deac0449524693a738cea45394be3d0fa Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 2 Sep 2021 12:41:27 -0400
Subject: fixes for making overlay ink stroke in doc decorations align with
 selected stroke.

---
 src/client/views/DocumentDecorations.scss |  5 +++++
 src/client/views/DocumentDecorations.tsx  | 22 ++++++++++++++++------
 2 files changed, 21 insertions(+), 6 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 316f63240..9479fd365 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -6,7 +6,12 @@ $linkGap : 3px;
     position: absolute;
     z-index: 2000;
 }
+.documentDecorations-inkstroke {
 
+  svg:not(:root) {
+    overflow: visible !important;
+  }
+}
 .documentDecorations-container {
     z-index: $docDecorations-zindex;
     position: absolute;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 244d14f3a..db3ec79a1 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -393,10 +393,10 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
         this._inkDragDocs.map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] }))
             .forEach(({ oldbds: { doc, x, y, width, height }, inkPts }) => {
                 Doc.GetProto(doc).data = new InkField(inkPts.map(ipt =>  // (new x — oldx) + newWidth * (oldxpoint /oldWidth)
-                ({
-                    X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width,
-                    Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height
-                })));
+                    ({
+                        X: (NumCast(doc.x) - x) + NumCast(doc.width) * ipt.X / width,
+                        Y: (NumCast(doc.y) - y) + NumCast(doc.height) * ipt.Y / height
+                    })));
                 Doc.SetNativeWidth(doc, undefined);
                 Doc.SetNativeHeight(doc, undefined);
             });
@@ -480,7 +480,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
             const scaleX = width === strokeWidth ? 1 : (this.props.PanelWidth - strokeWidth) / (width - strokeWidth);
             const scaleY = height === strokeWidth ? 1 : (this.props.PanelHeight - strokeWidth) / (height - strokeWidth);
 
-            selectedLine = InteractionUtils.CreatePolyline(inkData, left, top, Colors.MEDIUM_BLUE, 4, 4, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"),
+            selectedLine = InteractionUtils.CreatePolyline(inkData, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"),
                 StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false);
         }
 
@@ -502,7 +502,6 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
                 }}>
                     {!canDelete ? <div /> : topBtn("close", "times", undefined, this.onCloseClick, "Close")}
                     {seldoc.props.hideDecorationTitle || seldoc.props.Document.type === DocumentType.EQUATION ? (null) : titleArea}
-                    {selectedLine}
                     {seldoc.props.hideResizeHandles || seldoc.props.Document.type === DocumentType.EQUATION ? (null) :
                         <>
                             {SelectionManager.Views().length !== 1 || seldoc.Document.type === DocumentType.INK ? (null) :
@@ -525,6 +524,17 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
                         </>
                     }
                 </div >
+                <div className="documentDecorations-inkstroke" style={{
+                    position: "absolute",
+                    width: (bounds.r - bounds.x + this._resizeBorderWidth) + "px",
+                    height: (bounds.b - bounds.y + this._resizeBorderWidth) + "px",
+                    left: bounds.x,
+                    top: bounds.y,
+                    overflow: "visible",
+                    pointerEvents: "none",
+                }} >
+                    {selectedLine}
+                </div>
                 {seldoc?.Document.type === DocumentType.FONTICON ? (null) : <div className="link-button-container" key="links" style={{ left: bounds.x - this._resizeBorderWidth / 2 + 10, top: bounds.b + this._resizeBorderWidth / 2 }}>
                     <DocumentButtonBar views={SelectionManager.Views} />
                 </div>}
-- 
cgit v1.2.3-70-g09d2


From 7840b15be359c5ef3b7efd5154177d82e919c2d5 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 2 Sep 2021 12:49:51 -0400
Subject: fix for transforming inkpoints in docdecorations.

---
 src/client/views/DocumentDecorations.tsx | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index db3ec79a1..be9ab7960 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -464,13 +464,13 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
             const inkData = Cast(SelectionManager.Views().lastElement().rootDoc.data, InkField)?.inkData ?? [{ X: 0, Y: 0 }];
             const inkDoc = SelectionManager.Views().lastElement().layoutDoc;
 
-            inkData.map((point) => { docView.screenToLocal().inverse().transformPoint(point.X, point.Y); });
+            const points = inkData.map((point) => docView.screenToLocal().inverse().transformPoint(point.X, point.Y)).map(p => ({ X: p[0], Y: p[1] }));
 
             const strokeWidth = 4;
-            const lineTop = Math.min(...inkData.map(p => p.Y));
-            const lineBottom = Math.max(...inkData.map(p => p.Y));
-            const lineLeft = Math.min(...inkData.map(p => p.X));
-            const lineRight = Math.max(...inkData.map(p => p.X));
+            const lineTop = Math.min(...points.map(p => p.Y));
+            const lineBottom = Math.max(...points.map(p => p.Y));
+            const lineLeft = Math.min(...points.map(p => p.X));
+            const lineRight = Math.max(...points.map(p => p.X));
             const left = lineLeft - strokeWidth / 2;
             const top = lineTop - strokeWidth / 2;
             const right = lineRight + strokeWidth / 2;
@@ -480,7 +480,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
             const scaleX = width === strokeWidth ? 1 : (this.props.PanelWidth - strokeWidth) / (width - strokeWidth);
             const scaleY = height === strokeWidth ? 1 : (this.props.PanelHeight - strokeWidth) / (height - strokeWidth);
 
-            selectedLine = InteractionUtils.CreatePolyline(inkData, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"),
+            selectedLine = InteractionUtils.CreatePolyline(points, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"),
                 StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false);
         }
 
-- 
cgit v1.2.3-70-g09d2


From 57243cb00f2fd575e5d5d6a79108cb97793bc01c Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 2 Sep 2021 13:20:55 -0400
Subject: from last

---
 src/client/views/DocumentDecorations.tsx | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index be9ab7960..a615d8b26 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -463,25 +463,26 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
         if (useRotation && docView) {
             const inkData = Cast(SelectionManager.Views().lastElement().rootDoc.data, InkField)?.inkData ?? [{ X: 0, Y: 0 }];
             const inkDoc = SelectionManager.Views().lastElement().layoutDoc;
+            const swidth = docView.screenToLocal().inverse().transformDirection(NumCast(seldoc.props.Document.strokeWidth, 1), NumCast(seldoc.props.Document.strokeWidth, 1));
 
             const points = inkData.map((point) => docView.screenToLocal().inverse().transformPoint(point.X, point.Y)).map(p => ({ X: p[0], Y: p[1] }));
 
-            const strokeWidth = 4;
-            const lineTop = Math.min(...points.map(p => p.Y));
-            const lineBottom = Math.max(...points.map(p => p.Y));
-            const lineLeft = Math.min(...points.map(p => p.X));
-            const lineRight = Math.max(...points.map(p => p.X));
-            const left = lineLeft - strokeWidth / 2;
-            const top = lineTop - strokeWidth / 2;
-            const right = lineRight + strokeWidth / 2;
-            const bottom = lineBottom + strokeWidth / 2;
+            const strokeWidth = 1;
+            const lineTop = Math.min(...points.map(p => p.Y)) - swidth[0] / 2;
+            const lineBottom = Math.max(...points.map(p => p.Y)) + swidth[0] / 2;
+            const lineLeft = Math.min(...points.map(p => p.X)) - swidth[0] / 2;
+            const lineRight = Math.max(...points.map(p => p.X)) + swidth[0] / 2;
+            const left = lineLeft;
+            const top = lineTop;
+            const right = lineRight;
+            const bottom = lineBottom;
             const width = Math.max(1, right - left);
             const height = Math.max(1, bottom - top);
-            const scaleX = width === strokeWidth ? 1 : (this.props.PanelWidth - strokeWidth) / (width - strokeWidth);
-            const scaleY = height === strokeWidth ? 1 : (this.props.PanelHeight - strokeWidth) / (height - strokeWidth);
+            const scaleX = width === strokeWidth ? 1 : (bounds.r - bounds.x) / (width - strokeWidth);
+            const scaleY = height === strokeWidth ? 1 : (bounds.b - bounds.y) / (height - strokeWidth);
 
             selectedLine = InteractionUtils.CreatePolyline(points, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"),
-                StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false);
+                StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), scaleX, scaleY, "", "none", 1.0, false);
         }
 
         return (<div className="documentDecorations" style={{ background: CurrentUserUtils.ActiveDashboard?.darkScheme ? "dimgray" : "" }} >
@@ -526,8 +527,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
                 </div >
                 <div className="documentDecorations-inkstroke" style={{
                     position: "absolute",
-                    width: (bounds.r - bounds.x + this._resizeBorderWidth) + "px",
-                    height: (bounds.b - bounds.y + this._resizeBorderWidth) + "px",
+                    width: (bounds.r - bounds.x) + "px",
+                    height: (bounds.b - bounds.y) + "px",
                     left: bounds.x,
                     top: bounds.y,
                     overflow: "visible",
-- 
cgit v1.2.3-70-g09d2


From 24c1290cfe41ba9b7c1f1e0a9442f03b4af70c58 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 2 Sep 2021 14:57:28 -0400
Subject: corrected fix to drawing ink stroke in doc decorations overlay.

---
 src/client/views/DocumentDecorations.tsx | 51 +++++++++++++-----------------
 src/client/views/InkingStroke.tsx        | 54 ++++++++++++++++++--------------
 2 files changed, 52 insertions(+), 53 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index a615d8b26..ce33f488a 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -3,33 +3,33 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { Tooltip } from '@material-ui/core';
 import { action, computed, observable, reaction, runInAction } from "mobx";
 import { observer } from "mobx-react";
+import { DateField } from '../../fields/DateField';
 import { AclAdmin, AclEdit, DataSym, Doc, Field, HeightSym, WidthSym } from "../../fields/Doc";
 import { Document } from '../../fields/documentSchemas';
-import { HtmlField } from '../../fields/HtmlField';
 import { InkField } from "../../fields/InkField";
 import { ScriptField } from '../../fields/ScriptField';
 import { Cast, NumCast, StrCast } from "../../fields/Types";
 import { GetEffectiveAcl } from '../../fields/util';
-import { setupMoveUpEvents, emptyFunction, returnFalse } from "../../Utils";
-import { Docs, DocUtils } from "../documents/Documents";
+import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../Utils";
+import { Docs } from "../documents/Documents";
 import { DocumentType } from '../documents/DocumentTypes';
 import { CurrentUserUtils } from '../util/CurrentUserUtils';
 import { DragManager } from "../util/DragManager";
+import { InteractionUtils } from '../util/InteractionUtils';
 import { SelectionManager } from "../util/SelectionManager";
 import { SnappingManager } from '../util/SnappingManager';
 import { undoBatch, UndoManager } from "../util/UndoManager";
 import { CollectionDockingView } from './collections/CollectionDockingView';
 import { DocumentButtonBar } from './DocumentButtonBar';
 import './DocumentDecorations.scss';
+import { Colors } from './global/globalEnums';
 import { KeyManager } from './GlobalKeyHandler';
+import { InkingStroke } from './InkingStroke';
 import { InkStrokeProperties } from './InkStrokeProperties';
 import { LightboxView } from './LightboxView';
 import { DocumentView } from "./nodes/DocumentView";
-import React = require("react");
 import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
-import { DateField } from '../../fields/DateField';
-import { InteractionUtils } from '../util/InteractionUtils';
-import { Colors } from './global/globalEnums';
+import React = require("react");
 
 @observer
 export class DocumentDecorations extends React.Component<{ PanelWidth: number, PanelHeight: number, boundsLeft: number, boundsTop: number }, { value: string }> {
@@ -457,32 +457,23 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
         bounds.b = Math.max(bounds.y, Math.max(topBounds, Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight));
 
         const useRotation = seldoc.rootDoc.type === DocumentType.INK;
-        const docView = SelectionManager.Views().lastElement().docView;
+        const docView = seldoc.docView;
         let selectedLine = null;
 
         if (useRotation && docView) {
-            const inkData = Cast(SelectionManager.Views().lastElement().rootDoc.data, InkField)?.inkData ?? [{ X: 0, Y: 0 }];
-            const inkDoc = SelectionManager.Views().lastElement().layoutDoc;
-            const swidth = docView.screenToLocal().inverse().transformDirection(NumCast(seldoc.props.Document.strokeWidth, 1), NumCast(seldoc.props.Document.strokeWidth, 1));
-
-            const points = inkData.map((point) => docView.screenToLocal().inverse().transformPoint(point.X, point.Y)).map(p => ({ X: p[0], Y: p[1] }));
-
-            const strokeWidth = 1;
-            const lineTop = Math.min(...points.map(p => p.Y)) - swidth[0] / 2;
-            const lineBottom = Math.max(...points.map(p => p.Y)) + swidth[0] / 2;
-            const lineLeft = Math.min(...points.map(p => p.X)) - swidth[0] / 2;
-            const lineRight = Math.max(...points.map(p => p.X)) + swidth[0] / 2;
-            const left = lineLeft;
-            const top = lineTop;
-            const right = lineRight;
-            const bottom = lineBottom;
-            const width = Math.max(1, right - left);
-            const height = Math.max(1, bottom - top);
-            const scaleX = width === strokeWidth ? 1 : (bounds.r - bounds.x) / (width - strokeWidth);
-            const scaleY = height === strokeWidth ? 1 : (bounds.b - bounds.y) / (height - strokeWidth);
-
-            selectedLine = InteractionUtils.CreatePolyline(points, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"),
-                StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), scaleX, scaleY, "", "none", 1.0, false);
+            const inkData = Cast(seldoc.rootDoc.data, InkField)?.inkData ?? [{ X: 0, Y: 0 }];
+            const inkDoc = seldoc.layoutDoc;
+            const overlayInkWidth = 10;
+
+            const { inkScaleX, inkScaleY, inkStrokeWidth } = InkingStroke.inkScaling(inkDoc, inkData, docView.props.PanelWidth(), docView.props.PanelHeight());
+
+            const screenInkWidth = docView.screenToLocal().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth);
+            const screenPts = inkData.map(point => docView.screenToLocal().inverse().transformPoint(point.X * inkScaleX, point.Y * inkScaleY)).map(p => ({ X: p[0], Y: p[1] }));
+            const screenTop = Math.min(...screenPts.map(p => p.Y)) - screenInkWidth[0] / 2;
+            const screenLeft = Math.min(...screenPts.map(p => p.X)) - screenInkWidth[0] / 2;
+
+            selectedLine = InteractionUtils.CreatePolyline(screenPts, screenLeft, screenTop, Colors.MEDIUM_BLUE, overlayInkWidth, overlayInkWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"),
+                StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false);
         }
 
         return (<div className="documentDecorations" style={{ background: CurrentUserUtils.ActiveDashboard?.darkScheme ? "dimgray" : "" }} >
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index b619f858e..b8ab0c4d8 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -5,7 +5,7 @@ import { Doc } from "../../fields/Doc";
 import { documentSchema } from "../../fields/documentSchemas";
 import { InkData, InkField, InkTool } from "../../fields/InkField";
 import { makeInterface } from "../../fields/Schema";
-import { Cast, StrCast } from "../../fields/Types";
+import { Cast, StrCast, NumCast } from "../../fields/Types";
 import { TraceMobx } from "../../fields/util";
 import { setupMoveUpEvents, emptyFunction, returnFalse } from "../../Utils";
 import { CognitiveServices } from "../cognitive_services/CognitiveServices";
@@ -88,6 +88,24 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
         // }
     }
 
+    public static inkScaling(inkDoc: Doc, inkData: InkData, panelWidth: number, panelHeight: number) {
+        const inkStrokeWidth = NumCast(inkDoc.strokeWidth, 1);
+        const inkTop = Math.min(...inkData.map(p => p.Y)) - inkStrokeWidth / 2;
+        const inkBottom = Math.max(...inkData.map(p => p.Y)) + inkStrokeWidth / 2;
+        const inkLeft = Math.min(...inkData.map(p => p.X)) - inkStrokeWidth / 2;
+        const inkRight = Math.max(...inkData.map(p => p.X)) + inkStrokeWidth / 2;
+        const inkWidth = Math.max(1, inkRight - inkLeft);
+        const inkHeight = Math.max(1, inkBottom - inkTop);
+        return {
+            inkStrokeWidth,
+            inkTop,
+            inkLeft,
+            inkWidth,
+            inkHeight,
+            inkScaleX: inkHeight === inkStrokeWidth ? 1 : (panelWidth - inkStrokeWidth) / (inkWidth - inkStrokeWidth),
+            inkScaleY: inkWidth === inkStrokeWidth ? 1 : (panelHeight - inkStrokeWidth) / (inkHeight - inkStrokeWidth)
+        };
+    }
     render() {
         TraceMobx();
         this.toggleControlButton();
@@ -95,34 +113,24 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
         // Extracting the ink data and formatting information of the current ink stroke.
         const data: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
         const inkDoc: Doc = this.layoutDoc;
-        const strokeWidth = Number(this.layoutDoc.strokeWidth);
-        const lineTop = Math.min(...data.map(p => p.Y));
-        const lineBottom = Math.max(...data.map(p => p.Y));
-        const lineLeft = Math.min(...data.map(p => p.X));
-        const lineRight = Math.max(...data.map(p => p.X));
-        const left = lineLeft - strokeWidth / 2;
-        const top = lineTop - strokeWidth / 2;
-        const right = lineRight + strokeWidth / 2;
-        const bottom = lineBottom + strokeWidth / 2;
-        const width = Math.max(1, right - left);
-        const height = Math.max(1, bottom - top);
-        const scaleX = width === strokeWidth ? 1 : (this.props.PanelWidth() - strokeWidth) / (width - strokeWidth);
-        const scaleY = height === strokeWidth ? 1 : (this.props.PanelHeight() - strokeWidth) / (height - strokeWidth);
+
+        const { inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY, inkWidth, inkHeight } = InkingStroke.inkScaling(inkDoc, data, this.props.PanelWidth(), this.props.PanelHeight());
+
         const strokeColor = StrCast(this.layoutDoc.color, "");
-        const dotsize = Math.max(width * scaleX, height * scaleY) / 40;
+        const dotsize = Math.max(inkWidth * inkScaleX, inkHeight * inkScaleY) / 40;
 
         // Visually renders the polygonal line made by the user.
-        const inkLine = InteractionUtils.CreatePolyline(data, left, top, strokeColor, strokeWidth, strokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker),
-            StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", 1.0, false);
+        const inkLine = InteractionUtils.CreatePolyline(data, inkLeft, inkTop, strokeColor, inkStrokeWidth, inkStrokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker),
+            StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), inkScaleX, inkScaleY, "", "none", 1.0, false);
         // Thin blue line indicating that the current ink stroke is selected.
         // const selectedLine = InteractionUtils.CreatePolyline(data, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth / 6, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"),
         //     StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", 1.0, false);
         // Invisible polygonal line that enables the ink to be selected by the user.
-        const clickableLine = InteractionUtils.CreatePolyline(data, left, top, "transparent", strokeWidth, strokeWidth + 15, StrCast(this.layoutDoc.strokeBezier),
-            StrCast(this.layoutDoc.fillColor, "none"), "none", "none", undefined, scaleX, scaleY, "", this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted", 0.0, true);
+        const clickableLine = InteractionUtils.CreatePolyline(data, inkLeft, inkTop, "transparent", inkStrokeWidth, inkStrokeWidth + 15, StrCast(this.layoutDoc.strokeBezier),
+            StrCast(this.layoutDoc.fillColor, "none"), "none", "none", undefined, inkScaleX, inkScaleY, "", this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted", 0.0, true);
         // Set of points rendered upon the ink that can be added if a user clicks on one.
-        const addedPoints = InteractionUtils.CreatePoints(data, left, top, strokeColor, strokeWidth, strokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker),
-            StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5, false);
+        const addedPoints = InteractionUtils.CreatePoints(data, inkLeft, inkTop, strokeColor, inkStrokeWidth, inkStrokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker),
+            StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), inkScaleX, inkScaleY, "", "none", this.props.isSelected() && inkStrokeWidth <= 5, false);
 
         return (
             <svg className="inkStroke"
@@ -152,12 +160,12 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
                             inkDoc={inkDoc}
                             data={data}
                             addedPoints={addedPoints}
-                            format={[left, top, scaleX, scaleY, strokeWidth]}
+                            format={[lineLeft, lineTop, scaleX, scaleY, inkStrokeWidth]}
                             ScreenToLocalTransform={this.props.ScreenToLocalTransform} />
                         <InkHandles
                             inkDoc={inkDoc}
                             data={data}
-                            format={[left, top, scaleX, scaleY, strokeWidth]}
+                            format={[lineLeft, lineTop, scaleX, scaleY, inkStrokeWidth]}
                             ScreenToLocalTransform={this.props.ScreenToLocalTransform} />
                     </> : ""}
             </svg>
-- 
cgit v1.2.3-70-g09d2


From 610147f7d48ae5a8191fff45cb6d0a5e71bf94a5 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Thu, 2 Sep 2021 15:25:53 -0400
Subject: cleaned up overlay ink stroke in document decorations

---
 src/client/views/DocumentDecorations.scss |  3 ++
 src/client/views/DocumentDecorations.tsx  | 46 ++++++++++++-------------------
 src/client/views/InkingStroke.tsx         | 33 +++++++++++++++++-----
 src/client/views/nodes/DocumentView.tsx   |  1 +
 4 files changed, 48 insertions(+), 35 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 9479fd365..68e0d12d4 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -7,6 +7,9 @@ $linkGap : 3px;
     z-index: 2000;
 }
 .documentDecorations-inkstroke {
+    position: absolute;
+    overflow: visible;
+    pointer-events: none;
 
   svg:not(:root) {
     overflow: visible !important;
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index ce33f488a..3ffbb2904 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -457,23 +457,23 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
         bounds.b = Math.max(bounds.y, Math.max(topBounds, Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight));
 
         const useRotation = seldoc.rootDoc.type === DocumentType.INK;
-        const docView = seldoc.docView;
-        let selectedLine = null;
-
-        if (useRotation && docView) {
-            const inkData = Cast(seldoc.rootDoc.data, InkField)?.inkData ?? [{ X: 0, Y: 0 }];
-            const inkDoc = seldoc.layoutDoc;
-            const overlayInkWidth = 10;
-
-            const { inkScaleX, inkScaleY, inkStrokeWidth } = InkingStroke.inkScaling(inkDoc, inkData, docView.props.PanelWidth(), docView.props.PanelHeight());
-
-            const screenInkWidth = docView.screenToLocal().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth);
-            const screenPts = inkData.map(point => docView.screenToLocal().inverse().transformPoint(point.X * inkScaleX, point.Y * inkScaleY)).map(p => ({ X: p[0], Y: p[1] }));
-            const screenTop = Math.min(...screenPts.map(p => p.Y)) - screenInkWidth[0] / 2;
-            const screenLeft = Math.min(...screenPts.map(p => p.X)) - screenInkWidth[0] / 2;
-
-            selectedLine = InteractionUtils.CreatePolyline(screenPts, screenLeft, screenTop, Colors.MEDIUM_BLUE, overlayInkWidth, overlayInkWidth, StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"),
-                StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker), StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false);
+        const screenData = seldoc.ComponentView?.screenStrokeData?.();
+        let selectedLine = (null);
+        if (screenData) {
+            const inkDoc = seldoc.props.Document;
+            const overlayWidth = 10;
+            selectedLine = <div className="documentDecorations-inkstroke" style={{
+                width: (bounds.r - bounds.x) + "px",
+                height: (bounds.b - bounds.y) + "px",
+                left: bounds.x,
+                top: bounds.y,
+            }} >
+                {InteractionUtils.CreatePolyline(screenData.screenPts, screenData.screenLeft, screenData.screenTop, Colors.MEDIUM_BLUE, overlayWidth, overlayWidth,
+                    StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"),
+                    StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker),
+                    StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false)}
+
+            </div>
         }
 
         return (<div className="documentDecorations" style={{ background: CurrentUserUtils.ActiveDashboard?.darkScheme ? "dimgray" : "" }} >
@@ -516,17 +516,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
                         </>
                     }
                 </div >
-                <div className="documentDecorations-inkstroke" style={{
-                    position: "absolute",
-                    width: (bounds.r - bounds.x) + "px",
-                    height: (bounds.b - bounds.y) + "px",
-                    left: bounds.x,
-                    top: bounds.y,
-                    overflow: "visible",
-                    pointerEvents: "none",
-                }} >
-                    {selectedLine}
-                </div>
+                {selectedLine}
                 {seldoc?.Document.type === DocumentType.FONTICON ? (null) : <div className="link-button-container" key="links" style={{ left: bounds.x - this._resizeBorderWidth / 2 + 10, top: bounds.b + this._resizeBorderWidth / 2 }}>
                     <DocumentButtonBar views={SelectionManager.Views} />
                 </div>}
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index b8ab0c4d8..8461930bc 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -21,6 +21,7 @@ import { InkControls } from "./InkControls";
 import { InkHandles } from "./InkHandles";
 import { Colors } from "./global/globalEnums";
 import { GestureOverlay } from "./GestureOverlay";
+import { isThisTypeNode } from "typescript";
 
 type InkDocument = makeInterface<[typeof documentSchema]>;
 const InkDocument = makeInterface(documentSchema);
@@ -38,6 +39,10 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
         // this._previousColor = ActiveInkColor();
     }
 
+    componentDidMount() {
+        this.props.setContentView?.(this);
+    }
+
     public static LayoutString(fieldStr: string) {
         return FieldView.LayoutString(InkingStroke, fieldStr);
     }
@@ -88,8 +93,9 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
         // }
     }
 
-    public static inkScaling(inkDoc: Doc, inkData: InkData, panelWidth: number, panelHeight: number) {
-        const inkStrokeWidth = NumCast(inkDoc.strokeWidth, 1);
+    inkScaledData = () => {
+        const inkData: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
+        const inkStrokeWidth = NumCast(this.rootDoc.strokeWidth, 1);
         const inkTop = Math.min(...inkData.map(p => p.Y)) - inkStrokeWidth / 2;
         const inkBottom = Math.max(...inkData.map(p => p.Y)) + inkStrokeWidth / 2;
         const inkLeft = Math.min(...inkData.map(p => p.X)) - inkStrokeWidth / 2;
@@ -102,10 +108,23 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
             inkLeft,
             inkWidth,
             inkHeight,
-            inkScaleX: inkHeight === inkStrokeWidth ? 1 : (panelWidth - inkStrokeWidth) / (inkWidth - inkStrokeWidth),
-            inkScaleY: inkWidth === inkStrokeWidth ? 1 : (panelHeight - inkStrokeWidth) / (inkHeight - inkStrokeWidth)
+            inkScaleX: inkHeight === inkStrokeWidth ? 1 : (this.props.PanelWidth() - inkStrokeWidth) / (inkWidth - inkStrokeWidth),
+            inkScaleY: inkWidth === inkStrokeWidth ? 1 : (this.props.PanelHeight() - inkStrokeWidth) / (inkHeight - inkStrokeWidth)
         };
     }
+
+    screenStrokeData = () => {
+        const inkData: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
+        const { inkScaleX, inkScaleY, inkStrokeWidth } = this.inkScaledData();
+
+        const screenInkWidth = this.props.ScreenToLocalTransform().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth);
+        const screenPts = inkData.map(point => this.props.ScreenToLocalTransform().inverse().transformPoint(point.X * inkScaleX, point.Y * inkScaleY)).map(p => ({ X: p[0], Y: p[1] }));
+        const screenTop = Math.min(...screenPts.map(p => p.Y)) - screenInkWidth[0] / 2;
+        const screenLeft = Math.min(...screenPts.map(p => p.X)) - screenInkWidth[0] / 2;
+
+        return { screenPts, screenLeft, screenTop };
+    }
+
     render() {
         TraceMobx();
         this.toggleControlButton();
@@ -114,7 +133,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
         const data: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
         const inkDoc: Doc = this.layoutDoc;
 
-        const { inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY, inkWidth, inkHeight } = InkingStroke.inkScaling(inkDoc, data, this.props.PanelWidth(), this.props.PanelHeight());
+        const { inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY, inkWidth, inkHeight } = this.inkScaledData();
 
         const strokeColor = StrCast(this.layoutDoc.color, "");
         const dotsize = Math.max(inkWidth * inkScaleX, inkHeight * inkScaleY) / 40;
@@ -160,12 +179,12 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
                             inkDoc={inkDoc}
                             data={data}
                             addedPoints={addedPoints}
-                            format={[lineLeft, lineTop, scaleX, scaleY, inkStrokeWidth]}
+                            format={[inkLeft, inkTop, inkScaleX, inkScaleY, inkStrokeWidth]}
                             ScreenToLocalTransform={this.props.ScreenToLocalTransform} />
                         <InkHandles
                             inkDoc={inkDoc}
                             data={data}
-                            format={[lineLeft, lineTop, scaleX, scaleY, inkStrokeWidth]}
+                            format={[inkLeft, inkTop, inkScaleX, inkScaleY, inkStrokeWidth]}
                             ScreenToLocalTransform={this.props.ScreenToLocalTransform} />
                     </> : ""}
             </svg>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 745d58656..3587c1d2a 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -88,6 +88,7 @@ export interface DocComponentView {
     setKeyFrameEditing?: (set: boolean) => void; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown)
     playFrom?: (time: number, endTime?: number) => void;
     setFocus?: () => void;
+    screenStrokeData?: () => { screenPts: { X: number, Y: number }[], screenTop: number, screenLeft: number };
 }
 export interface DocumentViewSharedProps {
     renderDepth: number;
-- 
cgit v1.2.3-70-g09d2


From 15bc374105eb7c55493d9ca6c2b12f9bf22735c9 Mon Sep 17 00:00:00 2001
From: vkalev <vjk1883@gmail.com>
Date: Fri, 3 Sep 2021 13:18:46 -0400
Subject: adding ComponentDecorations

---
 src/client/views/ComponentDecorations.scss |   0
 src/client/views/ComponentDecorations.tsx  |  14 +
 src/client/views/DocumentDecorations.scss  | 631 ++++++++++++++---------------
 src/client/views/DocumentDecorations.tsx   |  19 -
 src/client/views/InkStroke.scss            |  11 +
 src/client/views/InkingStroke.tsx          |  18 +-
 src/client/views/MainView.tsx              |   2 +
 src/client/views/nodes/DocumentView.tsx    |   2 +-
 8 files changed, 354 insertions(+), 343 deletions(-)
 create mode 100644 src/client/views/ComponentDecorations.scss
 create mode 100644 src/client/views/ComponentDecorations.tsx

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

diff --git a/src/client/views/ComponentDecorations.scss b/src/client/views/ComponentDecorations.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/client/views/ComponentDecorations.tsx b/src/client/views/ComponentDecorations.tsx
new file mode 100644
index 000000000..66f81fe4f
--- /dev/null
+++ b/src/client/views/ComponentDecorations.tsx
@@ -0,0 +1,14 @@
+import { observer } from "mobx-react";
+import { SelectionManager } from "../util/SelectionManager";
+import './ComponentDecorations.scss';
+import React = require("react");
+
+@observer
+export class ComponentDecorations extends React.Component {
+    static Instance: ComponentDecorations;
+
+    render() {
+        const seldoc = SelectionManager.Views().lastElement();
+        return seldoc?.ComponentView?.componentUI?.() ?? (null);
+    }
+}
\ No newline at end of file
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 68e0d12d4..2e7142a8e 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -1,419 +1,408 @@
 @import "global/globalCssVariables";
 
-$linkGap : 3px;
+$linkGap: 3px;
 
 .documentDecorations {
-    position: absolute;
-    z-index: 2000;
-}
-.documentDecorations-inkstroke {
-    position: absolute;
-    overflow: visible;
-    pointer-events: none;
-
-  svg:not(:root) {
-    overflow: visible !important;
-  }
+  position: absolute;
+  z-index: 2000;
 }
 .documentDecorations-container {
-    z-index: $docDecorations-zindex;
+  z-index: $docDecorations-zindex;
+  position: absolute;
+  top: 0;
+  left: 0;
+  display: grid;
+  grid-template-rows: 20px 8px 1fr 8px;
+  grid-template-columns: 8px 16px 1fr 8px 8px;
+  pointer-events: none;
+
+  .documentDecorations-centerCont {
+    grid-column: 3;
+    background: none;
+  }
+
+  .documentDecorations-selectorButton {
+    pointer-events: auto;
+    height: 15px;
+    width: 15px;
+    left: -20px;
+    top: 20px;
+    display: inline-block;
     position: absolute;
-    top: 0;
-    left: 0;
-    display: grid;
-    grid-template-rows: 20px 8px 1fr 8px;
-    grid-template-columns: 8px 16px 1fr 8px 8px;
-    pointer-events: none;
-
-    .documentDecorations-centerCont {
-        grid-column: 3;
-        background: none;
-    }
+    opacity: 0.5;
+  }
 
-    .documentDecorations-selectorButton {
-        pointer-events: auto;
-        height: 15px;
-        width: 15px;
-        left: -20px;
-        top: 20px;
-        display: inline-block;
-        position: absolute;
-        opacity: 0.5;
-    }
+  .documentDecorations-radius {
+    pointer-events: auto;
+    opacity: 1;
+    transform: translate(10px, 10px);
+    grid-row: 4;
+  }
 
-    .documentDecorations-radius {
-        pointer-events: auto;
-        opacity: 1;
-        transform: translate(10px, 10px);
-        grid-row: 4;
+  .documentDecorations-topLeftResizer,
+  .documentDecorations-topRightResizer,
+  .documentDecorations-bottomLeftResizer,
+  .documentDecorations-bottomRightResizer,
+  .documentDecorations-leftResizer,
+  .documentDecorations-topResizer,
+  .documentDecorations-bottomResizer,
+  .documentDecorations-rightResizer {
+    pointer-events: auto;
+    background: $medium-gray;
+    opacity: 0.1;
+    &:hover {
+      opacity: 1;
     }
+  }
 
-    .documentDecorations-topLeftResizer,
-    .documentDecorations-topRightResizer,
-    .documentDecorations-bottomLeftResizer,
-    .documentDecorations-bottomRightResizer,
-    .documentDecorations-leftResizer,
-    .documentDecorations-topResizer,
-    .documentDecorations-bottomResizer,
-    .documentDecorations-rightResizer {
-        pointer-events: auto;
-        background: $medium-gray;
-        opacity: 0.1;
-        &:hover {
-            opacity: 1;
-        }
-    }
+  .documentDecorations-topLeftResizer,
+  .documentDecorations-leftResizer,
+  .documentDecorations-bottomLeftResizer {
+    grid-column: 1;
+  }
 
-    .documentDecorations-topLeftResizer,
-    .documentDecorations-leftResizer,
-    .documentDecorations-bottomLeftResizer {
-        grid-column: 1
-    }
+  .documentDecorations-topResizer,
+  .documentDecorations-bottomResizer {
+    grid-column-start: 2;
+    grid-column-end: 5;
+  }
 
-    .documentDecorations-topResizer,
-    .documentDecorations-bottomResizer {
-        grid-column-start: 2;
-        grid-column-end: 5;
-    }
+  .documentDecorations-bottomRightResizer,
+  .documentDecorations-topRightResizer,
+  .documentDecorations-rightResizer {
+    grid-column-start: 5;
+    grid-column-end: 7;
+  }
 
-    .documentDecorations-bottomRightResizer,
-    .documentDecorations-topRightResizer,
-    .documentDecorations-rightResizer {
-        grid-column-start: 5;
-        grid-column-end: 7;
-    }
+  .documentDecorations-rotation,
+  .documentDecorations-borderRadius {
+    grid-column: 5;
+    grid-row: 4;
+    border-radius: 100%;
+    background: black;
+    height: 8;
+    right: -12;
+    top: 12;
+    position: relative;
+    pointer-events: all;
+    cursor: nwse-resize;
 
-    .documentDecorations-rotation,
-    .documentDecorations-borderRadius {
-        grid-column: 5;
-        grid-row: 4;
-        border-radius: 100%;
-        background: black;
-        height: 8;
-        right: -12;
-        top: 12;
-        position: relative;
-        pointer-events: all;
-        cursor: nwse-resize;
-
-        .borderRadiusTooltip {
-            width: 10px;
-            height: 10px;
-            position: absolute;
-        }
+    .borderRadiusTooltip {
+      width: 10px;
+      height: 10px;
+      position: absolute;
     }
-    .documentDecorations-rotation {
-        background: transparent;
-        right: -15;
-    }
-
+  }
+  .documentDecorations-rotation {
+    background: transparent;
+    right: -15;
+  }
 
-    .documentDecorations-topLeftResizer,
-    .documentDecorations-bottomRightResizer {
-        cursor: nwse-resize;
-        background: unset;
-        opacity: 1;
-    }
+  .documentDecorations-topLeftResizer,
+  .documentDecorations-bottomRightResizer {
+    cursor: nwse-resize;
+    background: unset;
+    opacity: 1;
+  }
 
-    .documentDecorations-topLeftResizer {
-        border-left: 2px solid;
-        border-top: solid 2px;
-    }
+  .documentDecorations-topLeftResizer {
+    border-left: 2px solid;
+    border-top: solid 2px;
+  }
 
-    .documentDecorations-bottomRightResizer {
-        border-right: 2px solid;
-        border-bottom: solid 2px;
-    }
+  .documentDecorations-bottomRightResizer {
+    border-right: 2px solid;
+    border-bottom: solid 2px;
+  }
 
-    .documentDecorations-topLeftResizer:hover,
-    .documentDecorations-bottomRightResizer:hover {
-        opacity: 1;
-    }
+  .documentDecorations-topLeftResizer:hover,
+  .documentDecorations-bottomRightResizer:hover {
+    opacity: 1;
+  }
 
-    .documentDecorations-bottomRightResizer {
-        grid-row: 4;
-    }
+  .documentDecorations-bottomRightResizer {
+    grid-row: 4;
+  }
 
-    .documentDecorations-topRightResizer,
-    .documentDecorations-bottomLeftResizer {
-        cursor: nesw-resize;
-        background: unset;
-        opacity: 1;
-    }
+  .documentDecorations-topRightResizer,
+  .documentDecorations-bottomLeftResizer {
+    cursor: nesw-resize;
+    background: unset;
+    opacity: 1;
+  }
 
-    .documentDecorations-topRightResizer {
-        border-right: 2px solid;
-        border-top: 2px solid;
-    }
+  .documentDecorations-topRightResizer {
+    border-right: 2px solid;
+    border-top: 2px solid;
+  }
 
-    .documentDecorations-bottomLeftResizer {
-        border-left: 2px solid;
-        border-bottom: 2px solid;
-    }
+  .documentDecorations-bottomLeftResizer {
+    border-left: 2px solid;
+    border-bottom: 2px solid;
+  }
 
-    .documentDecorations-topRightResizer:hover,
-    .documentDecorations-bottomLeftResizer:hover {
-        cursor: nesw-resize;
-        background: black;
-        opacity: 1;
-    }
+  .documentDecorations-topRightResizer:hover,
+  .documentDecorations-bottomLeftResizer:hover {
+    cursor: nesw-resize;
+    background: black;
+    opacity: 1;
+  }
 
-    .documentDecorations-topResizer,
-    .documentDecorations-bottomResizer {
-        cursor: ns-resize;
-    }
+  .documentDecorations-topResizer,
+  .documentDecorations-bottomResizer {
+    cursor: ns-resize;
+  }
 
-    .documentDecorations-leftResizer,
-    .documentDecorations-rightResizer {
-        cursor: ew-resize;
-    }
+  .documentDecorations-leftResizer,
+  .documentDecorations-rightResizer {
+    cursor: ew-resize;
+  }
 
-    .documentDecorations-contextMenu {
-        width: 25px;
-        height: calc(100% + 8px); // 8px for the height of the top resizer bar
-        grid-column-start: 2;
-        grid-column-end: 2;
-        pointer-events: all;
-        padding-left: 5px;
-        cursor: pointer;
-    }
+  .documentDecorations-contextMenu {
+    width: 25px;
+    height: calc(100% + 8px); // 8px for the height of the top resizer bar
+    grid-column-start: 2;
+    grid-column-end: 2;
+    pointer-events: all;
+    padding-left: 5px;
+    cursor: pointer;
+  }
 
-    .documentDecorations-titleBackground {
-        background: #ffffffcf;
-        border-radius: 8px;
-        width: 100%;
-        height: 100%;
-        position: absolute;
-    }
+  .documentDecorations-titleBackground {
+    background: #ffffffcf;
+    border-radius: 8px;
+    width: 100%;
+    height: 100%;
+    position: absolute;
+  }
 
-    .documentDecorations-title {
-        opacity: 1;
-        grid-column-start: 2;
-        grid-column-end: 4;
-        pointer-events: auto;
-        overflow: hidden;
-        text-align: center;
-        display: flex;
-        margin-left: 5px;
-        height: 22px;
-        position: absolute;
-        .documentDecorations-titleSpan {
-            width: 100%;
-            border-radius: 8px;
-            background: #ffffffcf;
-            position: absolute;
-            display: inline-block;
-            cursor: move;
-        }
+  .documentDecorations-title {
+    opacity: 1;
+    grid-column-start: 2;
+    grid-column-end: 4;
+    pointer-events: auto;
+    overflow: hidden;
+    text-align: center;
+    display: flex;
+    margin-left: 5px;
+    height: 22px;
+    position: absolute;
+    .documentDecorations-titleSpan {
+      width: 100%;
+      border-radius: 8px;
+      background: #ffffffcf;
+      position: absolute;
+      display: inline-block;
+      cursor: move;
     }
+  }
 
-    .focus-visible {
-        margin-left: 0px;
-    }
+  .focus-visible {
+    margin-left: 0px;
+  }
 }
 
-
 .documentDecorations-iconifyButton {
-    opacity: 1;
-    grid-column-start: 4;
-    grid-column-end: 4;
-    pointer-events: all;
-    right: 0;
-    cursor: pointer;
-    position: absolute;
-    width: 20px;
+  opacity: 1;
+  grid-column-start: 4;
+  grid-column-end: 4;
+  pointer-events: all;
+  right: 0;
+  cursor: pointer;
+  position: absolute;
+  width: 20px;
 }
 
 .documentDecorations-openButton {
-    display: flex;
-    align-items: center;
-    opacity: 1;
-    grid-column-start: 5;
-    grid-column-end: 5;
-    pointer-events: all;
-    cursor: pointer;
+  display: flex;
+  align-items: center;
+  opacity: 1;
+  grid-column-start: 5;
+  grid-column-end: 5;
+  pointer-events: all;
+  cursor: pointer;
 }
 
 .documentDecorations-closeButton {
-    display: flex;
-    align-items: center;
-    opacity: 1;
-    grid-column-start: 1;
-    grid-column-end: 3;
-    pointer-events: all;
-    cursor: pointer;
-
-    >svg {
-        margin: 0;
-    }
+  display: flex;
+  align-items: center;
+  opacity: 1;
+  grid-column-start: 1;
+  grid-column-end: 3;
+  pointer-events: all;
+  cursor: pointer;
+
+  > svg {
+    margin: 0;
+  }
 }
 
 .documentDecorations-background {
-    background: lightblue;
-    position: absolute;
-    opacity: 0.1;
+  background: lightblue;
+  position: absolute;
+  opacity: 0.1;
 }
 
 .linkFlyout {
-    grid-column: 2/4;
+  grid-column: 2/4;
 }
 
 .linkButton-empty:hover {
-    background: $medium-gray;
-    transform: scale(1.05);
-    cursor: pointer;
+  background: $medium-gray;
+  transform: scale(1.05);
+  cursor: pointer;
 }
 
 .linkButton-nonempty:hover {
-    background: $medium-gray;
-    transform: scale(1.05);
-    cursor: pointer;
+  background: $medium-gray;
+  transform: scale(1.05);
+  cursor: pointer;
 }
 
 .link-button-container {
-    border-radius: 10px;
-    width: max-content;
-    height: auto;
-    display: flex;
-    flex-direction: row;
-    z-index: 998;
-    position: absolute;
-    justify-content: center;
-    align-items: center;
-    gap: 5px;
-    background: $medium-gray;
+  border-radius: 10px;
+  width: max-content;
+  height: auto;
+  display: flex;
+  flex-direction: row;
+  z-index: 998;
+  position: absolute;
+  justify-content: center;
+  align-items: center;
+  gap: 5px;
+  background: $medium-gray;
 }
 
 .linkButtonWrapper {
-    pointer-events: auto;
-    padding-right: 5px;
-    width: 25px;
+  pointer-events: auto;
+  padding-right: 5px;
+  width: 25px;
 }
 
 .linkButton-linker {
-    height: 20px;
-    width: 20px;
-    text-align: center;
-    border-radius: 50%;
-    pointer-events: auto;
-    color: $dark-gray;
-    border: $dark-gray 1px solid;
+  height: 20px;
+  width: 20px;
+  text-align: center;
+  border-radius: 50%;
+  pointer-events: auto;
+  color: $dark-gray;
+  border: $dark-gray 1px solid;
 }
 
 .linkButton-linker:hover {
-    cursor: pointer;
-    transform: scale(1.05);
+  cursor: pointer;
+  transform: scale(1.05);
 }
 
 .linkButton-empty,
 .linkButton-nonempty {
-    height: 20px;
-    width: 20px;
-    border-radius: 50%;
-    opacity: 0.9;
-    pointer-events: auto;
-    background-color: $dark-gray;
-    color: $white;
-    text-transform: uppercase;
-    letter-spacing: 2px;
-    font-size: 75%;
-    transition: transform 0.2s;
-    text-align: center;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-
-    &:hover {
-        background: $medium-gray;
-        transform: scale(1.05);
-        cursor: pointer;
-    }
+  height: 20px;
+  width: 20px;
+  border-radius: 50%;
+  opacity: 0.9;
+  pointer-events: auto;
+  background-color: $dark-gray;
+  color: $white;
+  text-transform: uppercase;
+  letter-spacing: 2px;
+  font-size: 75%;
+  transition: transform 0.2s;
+  text-align: center;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+
+  &:hover {
+    background: $medium-gray;
+    transform: scale(1.05);
+    cursor: pointer;
+  }
 }
 
 .templating-menu {
-    position: absolute;
-    pointer-events: auto;
-    text-transform: uppercase;
-    letter-spacing: 2px;
-    font-size: 75%;
-    transition: transform 0.2s;
-    text-align: center;
-    display: flex;
-    justify-content: center;
-    align-items: center;
+  position: absolute;
+  pointer-events: auto;
+  text-transform: uppercase;
+  letter-spacing: 2px;
+  font-size: 75%;
+  transition: transform 0.2s;
+  text-align: center;
+  display: flex;
+  justify-content: center;
+  align-items: center;
 }
 
 .documentdecorations-icon {
-    margin: 0px;
+  margin: 0px;
 }
 .templating-button,
 .docDecs-tagButton {
-    width: 20px;
-    height: 20px;
-    border-radius: 50%;
-    opacity: 0.9;
-    font-size: 14;
-    background-color: $dark-gray;
-    color: $white;
-    text-align: center;
-    cursor: pointer;
-
-    &:hover {
-        background: $medium-gray;
-        transform: scale(1.05);
-    }
+  width: 20px;
+  height: 20px;
+  border-radius: 50%;
+  opacity: 0.9;
+  font-size: 14;
+  background-color: $dark-gray;
+  color: $white;
+  text-align: center;
+  cursor: pointer;
+
+  &:hover {
+    background: $medium-gray;
+    transform: scale(1.05);
+  }
 }
 
 .documentDecorations-darkScheme {
-    background: dimgray;
+  background: dimgray;
 }
 
 #template-list {
-    position: absolute;
-    top: 25px;
-    left: 0px;
-    width: max-content;
-    font-family: $sans-serif;
-    font-size: 12px;
-    background-color: $light-gray;
-    padding: 2px 12px;
-    list-style: none;
-
-    .templateToggle,
-    .chromeToggle {
-        text-align: left;
-    }
+  position: absolute;
+  top: 25px;
+  left: 0px;
+  width: max-content;
+  font-family: $sans-serif;
+  font-size: 12px;
+  background-color: $light-gray;
+  padding: 2px 12px;
+  list-style: none;
+
+  .templateToggle,
+  .chromeToggle {
+    text-align: left;
+  }
 
-    input {
-        margin-right: 10px;
-    }
+  input {
+    margin-right: 10px;
+  }
 }
 
 @-moz-keyframes spin {
-    100% {
-        -moz-transform: rotate(360deg);
-    }
+  100% {
+    -moz-transform: rotate(360deg);
+  }
 }
 
 @-webkit-keyframes spin {
-    100% {
-        -webkit-transform: rotate(360deg);
-    }
+  100% {
+    -webkit-transform: rotate(360deg);
+  }
 }
 
 @keyframes spin {
-    100% {
-        -webkit-transform: rotate(360deg);
-        transform: rotate(360deg);
-    }
+  100% {
+    -webkit-transform: rotate(360deg);
+    transform: rotate(360deg);
+  }
 }
 
 @keyframes shadow-pulse {
-    0% {
-        box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.8);
-    }
+  0% {
+    box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.8);
+  }
 
-    100% {
-        box-shadow: 0 0 0 10px rgba(0, 255, 0, 0);
-    }
-}
\ No newline at end of file
+  100% {
+    box-shadow: 0 0 0 10px rgba(0, 255, 0, 0);
+  }
+}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 3ffbb2904..2348c897b 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -457,24 +457,6 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
         bounds.b = Math.max(bounds.y, Math.max(topBounds, Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight));
 
         const useRotation = seldoc.rootDoc.type === DocumentType.INK;
-        const screenData = seldoc.ComponentView?.screenStrokeData?.();
-        let selectedLine = (null);
-        if (screenData) {
-            const inkDoc = seldoc.props.Document;
-            const overlayWidth = 10;
-            selectedLine = <div className="documentDecorations-inkstroke" style={{
-                width: (bounds.r - bounds.x) + "px",
-                height: (bounds.b - bounds.y) + "px",
-                left: bounds.x,
-                top: bounds.y,
-            }} >
-                {InteractionUtils.CreatePolyline(screenData.screenPts, screenData.screenLeft, screenData.screenTop, Colors.MEDIUM_BLUE, overlayWidth, overlayWidth,
-                    StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"),
-                    StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker),
-                    StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false)}
-
-            </div>
-        }
 
         return (<div className="documentDecorations" style={{ background: CurrentUserUtils.ActiveDashboard?.darkScheme ? "dimgray" : "" }} >
             <div className="documentDecorations-background" style={{
@@ -516,7 +498,6 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
                         </>
                     }
                 </div >
-                {selectedLine}
                 {seldoc?.Document.type === DocumentType.FONTICON ? (null) : <div className="link-button-container" key="links" style={{ left: bounds.x - this._resizeBorderWidth / 2 + 10, top: bounds.b + this._resizeBorderWidth / 2 }}>
                     <DocumentButtonBar views={SelectionManager.Views} />
                 </div>}
diff --git a/src/client/views/InkStroke.scss b/src/client/views/InkStroke.scss
index 812a79bd5..8edefa07b 100644
--- a/src/client/views/InkStroke.scss
+++ b/src/client/views/InkStroke.scss
@@ -1,3 +1,14 @@
+.inkstroke-UI {
+  //   transform-origin: top left;
+  position: absolute;
+  overflow: visible;
+  pointer-events: none;
+
+  svg:not(:root) {
+    overflow: visible !important;
+  }
+}
+
 .inkStroke {
   mix-blend-mode: multiply;
   stroke-linejoin: round;
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 297b3333c..41fbe0d55 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -114,7 +114,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
         };
     }
 
-    screenStrokeData = () => {
+    componentUI = () => {
         const { inkData, inkScaleX, inkScaleY, inkStrokeWidth } = this.inkScaledData();
 
         const screenInkWidth = this.props.ScreenToLocalTransform().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth);
@@ -122,7 +122,21 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
         const screenTop = Math.min(...screenPts.map(p => p.Y)) - screenInkWidth[0] / 2;
         const screenLeft = Math.min(...screenPts.map(p => p.X)) - screenInkWidth[0] / 2;
 
-        return { screenPts, screenLeft, screenTop };
+        const inkDoc = this.props.Document;
+        
+        const overlayWidth = 5;
+        return <div className="inkstroke-UI" style={{
+            // width: (bounds.r - bounds.x) + "px",
+            // height: (bounds.b - bounds.y) + "px",
+            left: screenLeft,
+            top: screenTop,
+        }} >
+            {InteractionUtils.CreatePolyline(screenPts, screenLeft, screenTop, Colors.MEDIUM_BLUE, overlayWidth, overlayWidth,
+                StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"),
+                StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker),
+                StrCast(inkDoc.strokeDash), 1, 1, "", "none", 1.0, false)}
+
+        </div>
     }
 
     render() {
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 1ce363b0a..b81459075 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -39,6 +39,7 @@ import { CollectionViewType } from './collections/CollectionView';
 import { ContextMenu } from './ContextMenu';
 import { DictationOverlay } from './DictationOverlay';
 import { DocumentDecorations } from './DocumentDecorations';
+import { ComponentDecorations } from './ComponentDecorations';
 import { GestureOverlay } from './GestureOverlay';
 import { MENU_PANEL_WIDTH, SEARCH_PANEL_HEIGHT } from './global/globalCssVariables.scss';
 import { KeyManager } from './GlobalKeyHandler';
@@ -594,6 +595,7 @@ export class MainView extends React.Component {
             <GroupManager />
             <GoogleAuthenticationManager />
             <DocumentDecorations PanelWidth={this._windowWidth} PanelHeight={this._windowHeight} boundsLeft={this.leftOffset} boundsTop={this.topOffset} />
+            <ComponentDecorations />
             {this.search}
             {LinkDescriptionPopup.descriptionPopup ? <LinkDescriptionPopup /> : null}
             {DocumentLinksButton.LinkEditorDocView ? <LinkMenu docView={DocumentLinksButton.LinkEditorDocView} changeFlyout={emptyFunction} /> : (null)}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3587c1d2a..4e6ed40d1 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -88,7 +88,7 @@ export interface DocComponentView {
     setKeyFrameEditing?: (set: boolean) => void; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown)
     playFrom?: (time: number, endTime?: number) => void;
     setFocus?: () => void;
-    screenStrokeData?: () => { screenPts: { X: number, Y: number }[], screenTop: number, screenLeft: number };
+    componentUI?: () => JSX.Element;
 }
 export interface DocumentViewSharedProps {
     renderDepth: number;
-- 
cgit v1.2.3-70-g09d2


From f63b9d0876dc6a4389d1a9ced314968804061cb3 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 13 Sep 2021 11:56:55 -0400
Subject: fixed unfreezing (allow reflowing) of webBox's.  fixed initial size
 of text annotation box.

---
 src/client/views/DocumentDecorations.tsx           | 15 +++++++------
 src/client/views/nodes/WebBox.tsx                  | 26 +++++++++++++---------
 .../views/nodes/formattedText/FormattedTextBox.tsx |  8 +++++--
 3 files changed, 30 insertions(+), 19 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index a570bdb34..8bc167079 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -319,11 +319,12 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
                 let height = (doc._height || (nheight / nwidth * width));
                 height = !height || isNaN(height) ? 20 : height;
                 const scale = docView.props.ScreenToLocalTransform().Scale;
+                const canModifyNativeDim = e.ctrlKey || doc.allowReflow;
                 if (nwidth && nheight) {
                     if (nwidth / nheight !== width / height && !dragBottom) {
                         height = nheight / nwidth * width;
                     }
-                    if (e.ctrlKey && !dragBottom) { // ctrl key enables modification of the nativeWidth or nativeHeight durin the interaction
+                    if (canModifyNativeDim && !dragBottom) { // ctrl key enables modification of the nativeWidth or nativeHeight durin the interaction
                         if (Math.abs(dW) > Math.abs(dH)) dH = dW * nheight / nwidth;
                         else dW = dH * nwidth / nheight;
                     }
@@ -333,7 +334,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
                 doc.x = (doc.x || 0) + dX * (actualdW - width);
                 doc.y = (doc.y || 0) + dY * (actualdH - height);
                 const fixedAspect = (nwidth && nheight);
-                if (e.ctrlKey && [DocumentType.IMG, DocumentType.SCREENSHOT, DocumentType.VID].includes(doc.type as DocumentType)) {
+                if (canModifyNativeDim && [DocumentType.IMG, DocumentType.SCREENSHOT, DocumentType.VID].includes(doc.type as DocumentType)) {
                     dW !== 0 && runInAction(() => {
                         const dataDoc = doc[DataSym];
                         const nw = Doc.NativeWidth(dataDoc);
@@ -343,22 +344,22 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
                     });
                 }
                 else if (fixedAspect) {
-                    if ((Math.abs(dW) > Math.abs(dH) && (!dragBottom || !e.ctrlKey)) || dragRight) {
-                        if (dragRight && e.ctrlKey) {
+                    if ((Math.abs(dW) > Math.abs(dH) && (!dragBottom || !canModifyNativeDim)) || dragRight) {
+                        if (dragRight && canModifyNativeDim) {
                             doc._nativeWidth = actualdW / (doc._width || 1) * Doc.NativeWidth(doc);
                         } else {
                             if (!doc._fitWidth) doc._height = nheight / nwidth * actualdW;
-                            else if (!e.ctrlKey || dragBotRight) doc._height = actualdH;
+                            else if (!canModifyNativeDim || dragBotRight) doc._height = actualdH;
                         }
                         doc._width = actualdW;
                     }
                     else {
-                        if (dragBottom && (e.ctrlKey || docView.layoutDoc._fitWidth)) { // frozen web pages and others that fitWidth can't grow horizontally to match a vertical resize so the only choice is to change the nativeheight even if the ctrl key isn't used
+                        if (dragBottom && (canModifyNativeDim || docView.layoutDoc._fitWidth)) { // frozen web pages and others that fitWidth can't grow horizontally to match a vertical resize so the only choice is to change the nativeheight even if the ctrl key isn't used
                             doc._nativeHeight = actualdH / (doc._height || 1) * Doc.NativeHeight(doc);
                             doc._autoHeight = false;
                         } else {
                             if (!doc._fitWidth) doc._width = nwidth / nheight * actualdH;
-                            else if (!e.ctrlKey || dragBotRight) doc._width = actualdW;
+                            else if (!canModifyNativeDim || dragBotRight) doc._width = actualdW;
                         }
                         doc._height = actualdH;
                     }
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index 7e46d8433..adf84d810 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -69,13 +69,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     constructor(props: any) {
         super(props);
-        if (true) {// his.webField) {
-            Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(this.dataDoc) || 850);
-            Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || this.Document[HeightSym]() / this.Document[WidthSym]() * 850);
-        }
-        if (this.layoutDoc[this.fieldKey + "-contentWidth"] === undefined) {
-            this.layoutDoc[this.fieldKey + "-contentWidth"] = Doc.NativeWidth(this.layoutDoc);
-        }
+        // if (true) {// his.webField) {
+        //     Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(this.dataDoc) || 850);
+        //     Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || this.Document[HeightSym]() / this.Document[WidthSym]() * 850);
+        // }
     }
 
     async componentDidMount() {
@@ -323,13 +320,14 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
             if (future === undefined) this.dataDoc[this.fieldKey + "-future"] = new List<string>([this._url]);
             else this.dataDoc[this.fieldKey + "-future"] = new List<string>([...future, this._url]);
             this.dataDoc[this.fieldKey] = new WebField(new URL(history.pop()!));
+            console.log(this._urlHash);
             return true;
         }
         return false;
     }
 
     static urlHash = (s: string) => {
-        return s.split('').reduce((a: any, b: any) => { a = ((a << 5) - a) + b.charCodeAt(0); return a & a; }, 0);
+        return Math.abs(s.split('').reduce((a: any, b: any) => { a = ((a << 5) - a) + b.charCodeAt(0); return a & a; }, 0));
     }
 
     @action
@@ -397,7 +395,15 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
         const cm = ContextMenu.Instance;
         const funcs: ContextMenuProps[] = [];
         funcs.push({ description: (this.layoutDoc.useCors ? "Don't Use" : "Use") + " Cors", event: () => this.layoutDoc.useCors = !this.layoutDoc.useCors, icon: "snowflake" });
-        funcs.push({ description: (this.layoutDoc[this.fieldKey + "-contentWidth"] ? "Unfreeze" : "Freeze") + " Content Width", event: () => this.layoutDoc[this.fieldKey + "-contentWidth"] = this.layoutDoc[this.fieldKey + "-contentWidth"] ? undefined : Doc.NativeWidth(this.layoutDoc), icon: "snowflake" });
+        funcs.push({
+            description: (!this.layoutDoc.allowReflow ? "Allow" : "Prevent") + " Reflow", event: () => {
+                const nw = !this.layoutDoc.allowReflow ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.scaling?.() || 1);
+                this.layoutDoc.allowReflow = !nw;
+                if (nw) {
+                    Doc.SetInPlace(this.layoutDoc, this.fieldKey + "-nativeWidth", nw, true);
+                }
+            }, icon: "snowflake"
+        });
         funcs.push({ description: "Toggle Annotation View ", event: () => this.Document._showSidebar = !this.Document._showSidebar, icon: "expand-arrows-alt" });
         cm.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
     }
@@ -487,7 +493,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
 
     @computed get content() {
         return <div className={"webBox-cont" + (!this.props.docViewPath().lastElement()?.docView?._pendingDoubleClick && this.props.isContentActive() && CurrentUserUtils.SelectedTool === InkTool.None && !DocumentDecorations.Instance?.Interacting ? "-interactive" : "")}
-            style={{ width: NumCast(this.layoutDoc[this.fieldKey + "-contentWidth"]) || `${100 / (this.props.scaling?.() || 1)}%`, }}>
+            style={{ width: !this.layoutDoc.allowReflow ? NumCast(this.layoutDoc[this.fieldKey + "-nativeWidth"]) || `100%` : "100%", }}>
             {this.urlContent}
         </div>;
     }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index e7a44f113..4b540312e 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -818,11 +818,15 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         this._disposers.breakupDictation = reaction(() => DocumentManager.Instance.RecordingEvent, this.breakupDictation);
         this._disposers.autoHeight = reaction(() => this.autoHeight, autoHeight => autoHeight && this.tryUpdateScrollHeight());
         this._disposers.scrollHeight = reaction(() => ({ scrollHeight: this.scrollHeight, autoHeight: this.autoHeight, width: NumCast(this.layoutDoc._width) }),
-            ({ width, scrollHeight, autoHeight }) => width && autoHeight && this.resetNativeHeight(scrollHeight)
+            ({ width, scrollHeight, autoHeight }) => {
+                width && autoHeight && this.resetNativeHeight(scrollHeight);
+            }, { fireImmediately: true }
         );
         this._disposers.componentHeights = reaction(  // set the document height when one of the component heights changes and autoHeight is on
             () => ({ sidebarHeight: this.sidebarHeight, textHeight: this.textHeight, autoHeight: this.autoHeight, marginsHeight: this.autoHeightMargins }),
-            ({ sidebarHeight, textHeight, autoHeight, marginsHeight }) => autoHeight && this.props.setHeight(marginsHeight + Math.max(sidebarHeight, textHeight)));
+            ({ sidebarHeight, textHeight, autoHeight, marginsHeight }) => {
+                autoHeight && this.props.setHeight(marginsHeight + Math.max(sidebarHeight, textHeight));
+            }, { fireImmediately: true });
         this._disposers.links = reaction(() => DocListCast(this.Document.links), // if a link is deleted, then remove all hyperlinks that reference it from the text's marks
             newLinks => {
                 this._cachedLinks.forEach(l => !newLinks.includes(l) && this.RemoveLinkFromDoc(l));
-- 
cgit v1.2.3-70-g09d2


From d15841974305bf01251f60fa73a8464c7cb914fe Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 13 Sep 2021 17:35:17 -0400
Subject: fixed dragging document that is unselected by clicking on nested
 object in sidbear to not double-drag two items effectively deleting the
 sidebar document.  fixed undoing of document decorations topbar buttons.

---
 src/client/views/DocumentDecorations.tsx                  | 7 ++-----
 src/client/views/nodes/DocumentView.tsx                   | 1 +
 src/client/views/nodes/formattedText/FormattedTextBox.tsx | 2 +-
 3 files changed, 4 insertions(+), 6 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 8bc167079..6ca8dbec6 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -136,7 +136,6 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
         return true;
     }
 
-    @undoBatch
     onCloseClick = () => {
         const selected = SelectionManager.Views().slice();
         SelectionManager.DeselectAll();
@@ -153,8 +152,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
             return true;
         }, emptyFunction, this.onMaximizeClick, false, false);
     }
-    @undoBatch
-    @action
+
     onMaximizeClick = (e: any): void => {
         const selectedDocs = SelectionManager.Views();
         if (selectedDocs.length) {
@@ -176,7 +174,6 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
         SelectionManager.DeselectAll();
     }
 
-    @undoBatch
     onIconifyClick = (): void => {
         SelectionManager.Views().forEach(dv => dv?.iconify());
         SelectionManager.DeselectAll();
@@ -433,7 +430,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
         const topBtn = (key: string, icon: string, pointerDown: undefined | ((e: React.PointerEvent) => void), click: undefined | ((e: any) => void), title: string) => (
             <Tooltip key={key} title={<div className="dash-tooltip">{title}</div>} placement="top">
                 <div className={`documentDecorations-${key}Button`} onContextMenu={e => e.preventDefault()}
-                    onPointerDown={pointerDown ?? (e => setupMoveUpEvents(this, e, returnFalse, click!, emptyFunction))} >
+                    onPointerDown={pointerDown ?? (e => setupMoveUpEvents(this, e, returnFalse, emptyFunction, undoBatch(e => click!(e))))} >
                     <FontAwesomeIcon icon={icon as any} />
                 </div>
             </Tooltip>);
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 007dca0c4..1fcbffadd 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -536,6 +536,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     }
 
     onPointerMove = (e: PointerEvent): void => {
+        if (e.cancelBubble) return;
         if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool))) return;
         if (e.cancelBubble && this.props.isDocumentActive?.()) {
             document.removeEventListener("pointermove", this.onPointerMove); // stop listening to pointerMove if something else has stopPropagated it (e.g., the MarqueeView)
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index b1d4a79db..acc2892d8 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -216,7 +216,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         AnchorMenu.Instance.Status = "marquee";
 
         AnchorMenu.Instance.OnClick = (e: PointerEvent) => {
-            !this._showSidebar && this.toggleSidebar();
+            !this.layoutDoc.showSidebar && this.toggleSidebar();
             this._sidebarRef.current?.anchorMenuClick(this.getAnchor());
         };
         AnchorMenu.Instance.Highlight = action((color: string, isLinkButton: boolean) => {
-- 
cgit v1.2.3-70-g09d2


From a6c7dc12a4a6b2c51c0363876e892a1adb0b382a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 15 Sep 2021 10:02:55 -0400
Subject: fixed dragging so that only isDocumentActive documents are dragged
 (get move events)  which fixes a bug where a nested document and its
 container might both be dragged at the same time.

---
 src/client/util/DragManager.ts                            |  4 ++--
 src/client/views/DocumentDecorations.tsx                  |  2 +-
 src/client/views/nodes/DocumentView.tsx                   | 12 ++++++------
 src/client/views/nodes/formattedText/FormattedTextBox.tsx |  8 +++++---
 4 files changed, 14 insertions(+), 12 deletions(-)

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

diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index f7ef9ae6f..421e4c6bb 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -145,7 +145,7 @@ export namespace DragManager {
         removeDropProperties?: string[];
         moveDocument?: MoveFunction;
         removeDocument?: RemoveFunction;
-        isSelectionMove?: boolean; // indicates that an explicitly selected Document is being dragged.  this will suppress onDragStart scripts
+        isDocDecorationMove?: boolean; // Flags that Document decorations are used to drag document which allows suppression of onDragStart scripts
     }
     export class LinkDragData {
         constructor(dragView: DocumentView, linkSourceGetAnchor: () => Doc,) {
@@ -225,7 +225,7 @@ export namespace DragManager {
             if (docDragData && !docDragData.droppedDocuments.length) {
                 docDragData.dropAction = dragData.userDropAction || dragData.dropAction;
                 docDragData.droppedDocuments =
-                    await Promise.all(dragData.draggedDocuments.map(async d => !dragData.isSelectionMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) :
+                    await Promise.all(dragData.draggedDocuments.map(async d => !dragData.isDocDecorationMove && !dragData.userDropAction && ScriptCast(d.onDragStart) ? addAudioTag(ScriptCast(d.onDragStart).script.run({ this: d }).result) :
                         docDragData.dropAction === "alias" ? Doc.MakeAlias(d) :
                             docDragData.dropAction === "proto" ? Doc.GetProto(d) :
                                 docDragData.dropAction === "copy" ? (await Doc.MakeClone(d)).clone : d));
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 5ffdb8ea1..e70ce4664 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -122,7 +122,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
         const dragData = new DragManager.DocumentDragData(SelectionManager.Views().map(dv => dv.props.Document), dragDocView.props.dropAction);
         dragData.offset = dragDocView.props.ScreenToLocalTransform().transformDirection(e.x - left, e.y - top);
         dragData.moveDocument = dragDocView.props.moveDocument;
-        dragData.isSelectionMove = true;
+        dragData.isDocDecorationMove = true;
         dragData.canEmbed = dragTitle;
         this._hidden = this.Interacting = true;
         DragManager.StartDocumentDrag(SelectionManager.Views().map(dv => dv.ContentDiv!), dragData, e.x, e.y, {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index b680fcf3b..e8a78d75c 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -529,9 +529,11 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 // don't preventDefault anymore.  Goldenlayout, PDF text selection and RTF text selection all need it to go though
                 //if (this.props.isSelected(true) && this.rootDoc.type !== DocumentType.PDF && this.layoutDoc._viewType !== CollectionViewType.Docking) e.preventDefault();
             }
-            document.removeEventListener("pointermove", this.onPointerMove);
+            if (this.props.isDocumentActive?.()) {
+                document.removeEventListener("pointermove", this.onPointerMove);
+                document.addEventListener("pointermove", this.onPointerMove);
+            }
             document.removeEventListener("pointerup", this.onPointerUp);
-            document.addEventListener("pointermove", this.onPointerMove);
             document.addEventListener("pointerup", this.onPointerUp);
         }
     }
@@ -539,10 +541,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
     onPointerMove = (e: PointerEvent): void => {
         if (e.cancelBubble) return;
         if ((InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool))) return;
-        if (e.cancelBubble && this.props.isDocumentActive?.()) {
-            document.removeEventListener("pointermove", this.onPointerMove); // stop listening to pointerMove if something else has stopPropagated it (e.g., the MarqueeView)
-        }
-        else if (!e.cancelBubble && (this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
+
+        if ((this.props.isDocumentActive?.() || this.layoutDoc.onDragStart) && !this.layoutDoc._lockedPosition && !CurrentUserUtils.OverlayDocs.includes(this.layoutDoc)) {
             if (Math.abs(this._downX - e.clientX) > 3 || Math.abs(this._downY - e.clientY) > 3) {
                 if (!e.altKey && (!this.topMost || this.layoutDoc.onDragStart || this.onClickHandler) && (e.buttons === 1 || InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE))) {
                     document.removeEventListener("pointermove", this.onPointerMove);
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index acc2892d8..caca215e5 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -435,10 +435,12 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         view.dispatch(view.state.tr.removeMark(start, end, nmark).addMark(start, end, nmark));
     }
     protected createDropTarget = (ele: HTMLDivElement) => {
-        this.ProseRef = ele;
-        this.setupEditor(this.config, this.props.fieldKey);
         this._dropDisposer?.();
-        ele && (this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.layoutDoc));
+        this.ProseRef = ele;
+        if (ele) {
+            this.setupEditor(this.config, this.props.fieldKey);
+            this._dropDisposer = DragManager.MakeDropTarget(ele, this.drop.bind(this), this.layoutDoc);
+        }
         // if (this.autoHeight) this.tryUpdateScrollHeight(); 
     }
 
-- 
cgit v1.2.3-70-g09d2


From ed1897d66ef9c982dabc4b4fc4b05d0fb072a127 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Wed, 15 Sep 2021 12:30:53 -0400
Subject: prevent groups from being opened in lightbox because its odd and
 there are bugs.  prevent tabViews from being switchable into a group because
 its odd.

---
 src/client/views/DocumentDecorations.tsx | 2 +-
 src/client/views/PropertiesButtons.tsx   | 4 +++-
 2 files changed, 4 insertions(+), 2 deletions(-)

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

diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index e70ce4664..6f9697703 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -420,7 +420,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number, P
         if (SnappingManager.GetIsDragging() || bounds.r - bounds.x < 1 || bounds.x === Number.MAX_VALUE || !seldoc || this._hidden || isNaN(bounds.r) || isNaN(bounds.b) || isNaN(bounds.x) || isNaN(bounds.y)) {
             return (null);
         }
-        const canOpen = SelectionManager.Views().some(docView => !docView.props.Document._stayInCollection);
+        const canOpen = SelectionManager.Views().some(docView => !docView.props.Document._stayInCollection && !docView.props.Document.isGroup);
         const canDelete = SelectionManager.Views().some(docView => {
             const collectionAcl = docView.props.ContainingCollectionView ? GetEffectiveAcl(docView.props.ContainingCollectionDoc?.[DataSym]) : AclEdit;
             return (!docView.rootDoc._stayInCollection || docView.rootDoc.isInkMask) &&
diff --git a/src/client/views/PropertiesButtons.tsx b/src/client/views/PropertiesButtons.tsx
index e3da7ce2a..e3de80009 100644
--- a/src/client/views/PropertiesButtons.tsx
+++ b/src/client/views/PropertiesButtons.tsx
@@ -32,6 +32,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
     @observable public static Instance: PropertiesButtons;
 
     @computed get selectedDoc() { return SelectionManager.SelectedSchemaDoc() || SelectionManager.Views().lastElement()?.rootDoc; }
+    @computed get selectedTabView() { return !SelectionManager.SelectedSchemaDoc() && SelectionManager.Views().lastElement()?.topMost; }
 
     propertyToggleBtn = (label: string, property: string, tooltip: (on?: any) => string, icon: (on: boolean) => string, onClick?: (dv: Opt<DocumentView>, doc: Doc, property: string) => void, useUserDoc?: boolean) => {
         const targetDoc = useUserDoc ? Doc.UserDoc() : this.selectedDoc;
@@ -214,6 +215,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
         const isStacking = this.selectedDoc?._viewType === CollectionViewType.Stacking;
         const isFreeForm = this.selectedDoc?._viewType === CollectionViewType.Freeform;
         const isTree = this.selectedDoc?._viewType === CollectionViewType.Tree;
+        const isTabView = this.selectedTabView;
         const toggle = (ele: JSX.Element | null, style?: React.CSSProperties) => <div className="propertiesButtons-button" style={style}> {ele} </div>;
         const isNovice = Doc.UserDoc().noviceMode;
         return !this.selectedDoc ? (null) :
@@ -229,7 +231,7 @@ export class PropertiesButtons extends React.Component<{}, {}> {
                 {toggle(this.maskButton, { display: !isInk ? "none" : "" })}
                 {toggle(this.chromeButton, { display: !isCollection || isNovice ? "none" : "" })}
                 {toggle(this.gridButton, { display: !isCollection ? "none" : "" })}
-                {toggle(this.groupButton, { display: !isCollection ? "none" : "" })}
+                {toggle(this.groupButton, { display: isTabView || !isCollection ? "none" : "" })}
                 {toggle(this.snapButton, { display: !isCollection ? "none" : "" })}
                 {toggle(this.clustersButton, { display: !isFreeForm ? "none" : "" })}
                 {toggle(this.panButton, { display: !isFreeForm ? "none" : "" })}
-- 
cgit v1.2.3-70-g09d2

