From ba0d831691e81903ab1fb9482ba5dcad0a769881 Mon Sep 17 00:00:00 2001
From: Lionel Han <47760119+IGoByJoe@users.noreply.github.com>
Date: Thu, 11 Jun 2020 23:40:49 -0700
Subject: functioning with new ink

---
 .../collections/collectionFreeForm/InkOptionsMenu.tsx    | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
index 5a27f74e5..46f7bc2e2 100644
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
@@ -11,6 +11,8 @@ import { Utils } from "../../../../Utils";
 import GestureOverlay from "../../GestureOverlay";
 import { Doc } from "../../../../fields/Doc";
 
+
+
 @observer
 export default class InkOptionsMenu extends AntimodeMenu {
     static Instance: InkOptionsMenu;
@@ -23,6 +25,8 @@ export default class InkOptionsMenu extends AntimodeMenu {
     @observable _colorBtn = false;
     @observable _widthBtn = false;
 
+
+
     constructor(props: Readonly<{}>) {
         super(props);
         InkOptionsMenu.Instance = this;
@@ -113,7 +117,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
             title="Bezier changer"
             key="bezier"
             onPointerDown={e => this.changeBezier(e)}
-            style={ { backgroundColor:ActiveInkBezierApprox() ? "121212":"" } }>
+            style={{ backgroundColor: ActiveInkBezierApprox() ? "121212" : "" }}>
             B
         </button>;
     }
@@ -126,7 +130,15 @@ export default class InkOptionsMenu extends AntimodeMenu {
             this.widthPicker,
             this.colorPicker,
         ];
-        return this.getElement(buttons);
+
+        const mobileButtons = [
+            this.shapeButtons,
+            this.bezierButton,
+            this.widthPicker,
+            this.colorPicker,
+        ];
+
+        return (window.innerWidth < 1000 ? this.getElement(mobileButtons) : this.getElement(buttons));
     }
 }
 Scripting.addGlobal(function activatePen(penBtn: any) {
-- 
cgit v1.2.3-70-g09d2


From 87aa11c70be1ae0270c69adc0c1e0219f79ce820 Mon Sep 17 00:00:00 2001
From: geireann <60007097+geireann@users.noreply.github.com>
Date: Tue, 16 Jun 2020 01:34:12 +0800
Subject: uploader + menu changes

image upload w/ video and other files
menu updates
---
 src/client/util/CurrentUserUtils.ts                |  23 +--
 src/client/views/GestureOverlay.scss               |   2 +-
 .../views/collections/CollectionStackingView.scss  |  10 +-
 .../collectionFreeForm/InkOptionsMenu.tsx          |   4 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |   2 +-
 .../views/presentationview/PresElementBox.tsx      |   2 +-
 src/mobile/ImageUpload.scss                        |   1 +
 src/mobile/ImageUpload.tsx                         | 139 +++++++++---------
 src/mobile/MobileInterface.tsx                     | 156 ++-------------------
 src/mobile/MobileMenu.scss                         |   8 +-
 10 files changed, 109 insertions(+), 238 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx')

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 1b0622f6d..e1605473c 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -329,7 +329,8 @@ export class CurrentUserUtils {
             doc.emptyWebpage = Docs.Create.WebDocument("", { title: "New Webpage", _nativeWidth: 850, _nativeHeight: 962, _width: 600, UseCors: true });
         }
         if (doc.activeMobile === undefined) {
-            doc.activeMobile = CurrentUserUtils.setupMobileMenu();
+            console.log("phone setup");
+            this.setupActiveMobile(doc);
         }
         return [
             { title: "Drag a comparison box", label: "Comp", icon: "columns", ignoreClick: true, drag: 'Docs.Create.ComparisonDocument()' },
@@ -398,16 +399,18 @@ export class CurrentUserUtils {
         return doc.myItemCreators as Doc;
     }
 
-    // static setupActiveMobile(doc: Doc) {
-    //     if (doc.activeMobile === undefined) {
-    //         doc.activeMobile = CurrentUserUtils.setupMobileMenu();
-    //     }
-    // }
+    static setupActiveMobile(doc: Doc) {
+        if (doc.activeMobile === undefined) {
+            console.log("undefined");
+            doc.activeMobile = this.setupMobileMenu();
+        }
+        return doc.activeMobile as Doc;
+    }
 
     static setupMobileMenu() {
-        const menu = Cast(Docs.Create.StackingDocument(CurrentUserUtils.setupMobileButtons(), {
-            _width: 980, ignoreClick: true, lockedPosition: true, _chromeStatus: "disabled", title: "home", _yMargin: 100
-        }), Doc) as Doc;
+        const menu = new PrefetchProxy(Docs.Create.StackingDocument(this.setupMobileButtons(), {
+            _width: 980, ignoreClick: true, lockedPosition: false, _chromeStatus: "disabled", title: "home", _yMargin: 100
+        }));
         return menu;
     }
 
@@ -740,7 +743,7 @@ export class CurrentUserUtils {
         this.setupDefaultIconTemplates(doc);  // creates a set of icon templates triggered by the document deoration icon
         this.setupDocTemplates(doc); // sets up the template menu of templates
         this.setupRightSidebar(doc);  // sets up the right sidebar collection for mobile upload documents and sharing
-        // this.setupActiveMobile(doc);
+        this.setupActiveMobile(doc);
         this.setupOverlays(doc);  // documents in overlay layer
         this.setupDockedButtons(doc);  // the bottom bar of font icons
         this.setupDefaultPresentation(doc); // presentation that's initially triggered
diff --git a/src/client/views/GestureOverlay.scss b/src/client/views/GestureOverlay.scss
index 107077792..f61f4a05e 100644
--- a/src/client/views/GestureOverlay.scss
+++ b/src/client/views/GestureOverlay.scss
@@ -1,7 +1,7 @@
 .gestureOverlay-cont {
     width: 100vw;
     height: 100vh;
-    position: absolute;
+    position: fixed;
     top: 0;
     left: 0;
     touch-action: none;
diff --git a/src/client/views/collections/CollectionStackingView.scss b/src/client/views/collections/CollectionStackingView.scss
index 714ff46a9..98efdfd23 100644
--- a/src/client/views/collections/CollectionStackingView.scss
+++ b/src/client/views/collections/CollectionStackingView.scss
@@ -428,11 +428,9 @@
 
     .collectionStackingView .collectionStackingView-columnDragger,
     .collectionMasonryView .collectionStackingView-columnDragger {
-        width: 30;
-        transform: translate(0, -40px);
-        height: 30;
-        font-size: 40;
-        position: absolute;
-        margin-left: -5;
+        width: 0.1;
+        height: 0.1;
+        opacity: 0;
+        font-size: 0;
     }
 }
\ No newline at end of file
diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
index 5a27f74e5..9f5e217bf 100644
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
@@ -101,7 +101,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
                 title={`Draw ${btn}`}
                 key={btn}
                 onPointerDown={action(e => GestureOverlay.Instance.InkShape = btn)}
-                style={{ backgroundColor: btn === GestureOverlay.Instance.InkShape ? "121212" : "" }}>
+                style={{ backgroundColor: btn === GestureOverlay.Instance?.InkShape ? "121212" : "" }}>
                 {this._icons[i]}
             </button>)},
         </>;
@@ -113,7 +113,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
             title="Bezier changer"
             key="bezier"
             onPointerDown={e => this.changeBezier(e)}
-            style={ { backgroundColor:ActiveInkBezierApprox() ? "121212":"" } }>
+            style={{ backgroundColor: ActiveInkBezierApprox() ? "121212" : "" }}>
             B
         </button>;
     }
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 1fab54d7e..e034e07a0 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -1213,7 +1213,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
         const rounded = StrCast(this.layoutDoc.borderRounding) === "100%" ? "-rounded" : "";
         const interactive = Doc.GetSelectedTool() === InkTool.None && !this.layoutDoc.isBackground;
         if (this.props.isSelected()) {
-            this._editorView && RichTextMenu.Instance.updateFromDash(this._editorView, undefined, this.props);
+            this._editorView && RichTextMenu.Instance?.updateFromDash(this._editorView, undefined, this.props);
         } else if (FormattedTextBoxComment.textBox === this) {
             FormattedTextBoxComment.Hide();
         }
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx
index caee06d8f..793d4068f 100644
--- a/src/client/views/presentationview/PresElementBox.tsx
+++ b/src/client/views/presentationview/PresElementBox.tsx
@@ -49,7 +49,7 @@ export class PresElementBox extends ViewBoxBaseComponent<FieldViewProps, PresDoc
 
     componentDidMount() {
         this._heightDisposer = reaction(() => [this.rootDoc.presExpandInlineButton, this.collapsedHeight],
-            params => this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 100 : 0), { fireImmediately: true });
+            params => this.layoutDoc._height = NumCast(params[1]) + (Number(params[0]) ? 200 : 0), { fireImmediately: true });
     }
     componentWillUnmount() {
         this._heightDisposer?.();
diff --git a/src/mobile/ImageUpload.scss b/src/mobile/ImageUpload.scss
index d5ab31469..95c0c2680 100644
--- a/src/mobile/ImageUpload.scss
+++ b/src/mobile/ImageUpload.scss
@@ -6,6 +6,7 @@
     flex-direction: column;
     align-items: center;
     max-width: 400px;
+    min-width: 400px;
 
     .upload_label {
         font-size: 3em;
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index 8f050aedd..3b4008e3f 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -14,6 +14,7 @@ import { listSpec } from '../fields/Schema';
 import { List } from '../fields/List';
 import { Scripting } from '../client/util/Scripting';
 import MainViewModal from '../client/views/MainViewModal';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 
 export interface ImageUploadProps {
     Document: Doc;
@@ -35,83 +36,80 @@ export class Uploader extends React.Component {
     @observable process: string = "";
 
     onClick = async () => {
-        console.log("uploader click");
         try {
-            this.status = "initializing protos";
+            await Docs.Prototypes.initialize();
+            const imgPrev = document.getElementById("img_preview");
             const slab1 = document.getElementById("slab1");
             if (slab1) {
                 slab1.style.opacity = "1";
             }
-            await Docs.Prototypes.initialize();
-            const imgPrev = document.getElementById("img_preview");
-            console.log("buddy");
             if (imgPrev) {
-                console.log("hi");
                 const files: FileList | null = inputRef.current!.files;
+                const slab2 = document.getElementById("slab2");
+                if (slab2) {
+                    slab2.style.opacity = "1";
+                }
                 if (files && files.length !== 0) {
-                    this.process = "Uploading Image"
-                    console.log(files[0]);
-                    const name = files[0].name;
-                    const res = await Networking.UploadFilesToServer(files[0]);
-                    this.status = "uploading image";
-                    const slab2 = document.getElementById("slab2");
-                    if (slab2) {
-                        slab2.style.opacity = "1";
-                    }
-                    this.status = "upload image, getting json";
-                    const slab3 = document.getElementById("slab3");
-                    if (slab3) {
-                        slab3.style.opacity = "1";
-                    }
-                    res.map(async ({ result }) => {
-                        if (result instanceof Error) {
-                            return;
-                        }
-                        const path = Utils.prepend(result.accessPaths.agnostic.client);
-                        const doc = Docs.Create.ImageDocument(path, { _nativeWidth: 200, _width: 200, title: name });
-
-                        this.status = "getting user document";
-                        const slab4 = document.getElementById("slab4");
-                        if (slab4) {
-                            slab4.style.opacity = "1";
-                        }
-                        this.status = "upload image, getting json";
-                        const slab5 = document.getElementById("slab5");
-                        if (slab5) {
-                            slab5.style.opacity = "1";
+                    this.process = "Uploading Files";
+                    for (let index = 0; index < files.length; ++index) {
+                        const file = files[index];
+                        const res = await Networking.UploadFilesToServer(file);
+                        const slab3 = document.getElementById("slab3");
+                        if (slab3) {
+                            slab3.style.opacity = "1";
                         }
-                        const res = await rp.get(Utils.prepend("/getUserDocumentId"));
-                        if (!res) {
-                            throw new Error("No user id returned");
-                        }
-                        const field = await DocServer.GetRefField(res);
-                        let pending: Opt<Doc>;
-                        if (field instanceof Doc) {
-                            pending = await Cast(field.rightSidebarCollection, Doc);
-                        }
-                        if (pending) {
-                            this.status = "has pending docs";
-                            const slab6 = document.getElementById("slab6");
-                            if (slab6) {
-                                slab6.style.opacity = "1";
+                        res.map(async ({ result }) => {
+                            const name = file.name;
+                            if (result instanceof Error) {
+                                return;
                             }
-                            const data = await Cast(pending.data, listSpec(Doc));
-                            if (data) {
-                                data.push(doc);
+                            const path = Utils.prepend(result.accessPaths.agnostic.client);
+                            let doc = null;
+                            if (file.type === "video/mp4") {
+                                doc = Docs.Create.VideoDocument(path, { _nativeWidth: 200, _width: 200, title: name });
                             } else {
-                                pending.data = new List([doc]);
+                                doc = Docs.Create.ImageDocument(path, { _nativeWidth: 200, _width: 200, title: name });
                             }
-                            this.status = "finished";
-
-                            console.log("hi");
-                            const slab7 = document.getElementById("slab7");
-                            if (slab7) {
-                                slab7.style.opacity = "1";
+                            const slab4 = document.getElementById("slab4");
+                            if (slab4) {
+                                slab4.style.opacity = "1";
+                            }
+                            const res = await rp.get(Utils.prepend("/getUserDocumentId"));
+                            if (!res) {
+                                throw new Error("No user id returned");
+                            }
+                            const field = await DocServer.GetRefField(res);
+                            let pending: Opt<Doc>;
+                            if (field instanceof Doc) {
+                                pending = await Cast(field.rightSidebarCollection, Doc);
                             }
-                            this.process = "Image Uploaded";
+                            if (pending) {
+                                const data = await Cast(pending.data, listSpec(Doc));
+                                if (data) {
+                                    data.push(doc);
+                                } else {
+                                    pending.data = new List([doc]);
+                                }
+                                this.status = "finished";
+                                const slab5 = document.getElementById("slab5");
+                                if (slab5) {
+                                    slab5.style.opacity = "1";
+                                }
+                                this.process = "File " + (index + 1).toString() + " Uploaded";
+                                if (index === files.length) {
+                                    const slab6 = document.getElementById("slab6");
+                                    if (slab6) {
+                                        slab6.style.opacity = "1";
+                                    }
+                                }
+                            }
+                        });
+                        this.process = "All Files Uploaded";
+                        const slab7 = document.getElementById("slab7");
+                        if (slab7) {
+                            slab7.style.opacity = "1";
                         }
-
-                    });
+                    }
                 } else {
                     this.process = "No file selected";
                 }
@@ -120,16 +118,18 @@ export class Uploader extends React.Component {
         } catch (error) {
             this.error = JSON.stringify(error);
         }
-
     }
 
     // Updates label after a files is selected (so user knows a file is uploaded)
     inputLabel = async () => {
         const files: FileList | null = inputRef.current!.files;
         await files;
-        if (files && files.length !== 0) {
+        if (files && files.length === 1) {
             console.log(files);
             this.nm = files[0].name;
+        } else if (files && files.length > 1) {
+            console.log(files.length);
+            this.nm = files.length.toString() + " files selected";
         }
     }
 
@@ -163,7 +163,7 @@ export class Uploader extends React.Component {
         if (slab7) {
             slab7.style.opacity = "0.4";
         }
-        this.nm = "Choose an image";
+        this.nm = "Choose files";
 
         if (inputRef.current) {
             inputRef.current.value = "";
@@ -177,9 +177,12 @@ export class Uploader extends React.Component {
     private get uploadInterface() {
         return (
             <div className="imgupload_cont">
-                <input type="file" accept="image/*" className="inputFile" id="input_image_file" ref={inputRef} onChange={this.inputLabel}></input>
+                <input type="file" accept="video/*,image/*" className="inputFile" id="input_image_file" ref={inputRef} onChange={this.inputLabel} multiple></input>
                 <label className="file" id="label" htmlFor="input_image_file">{this.nm}</label>
-                <div className="upload_label" onClick={this.onClick}>Upload Image</div>
+                <div className="upload_label" onClick={this.onClick}>
+                    <FontAwesomeIcon icon="upload" size="lg" />
+                    Upload
+                </div>
                 {/* <div onClick={this.onClick} className="upload_button">Upload</div> */}
                 <img id="img_preview" src=""></img>
                 {/* <p>{this.status}</p>
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index f2914eaae..211cc7a1a 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -52,10 +52,7 @@ export class MobileInterface extends React.Component {
     @observable static Instance: MobileInterface;
     @computed private get userDoc() { return Doc.UserDoc(); }
     @computed private get mainContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeMobile, Doc)) : CurrentUserUtils.GuestMobile; }
-    // @computed private get activeContainer() { return this.userDoc ? FieldValue(Cast(this.userDoc.activeMobile, Doc)) : CurrentUserUtils.GuestMobile; }
-    // Sets up new mobile menu only if activeMobile already exists
-    // @observable private mainDoc: any = this.userDoc.activeMobile === undefined ? CurrentUserUtils.setupMobileMenu() : this.userDoc.activeMobile;
-    @observable private mainDoc: any = CurrentUserUtils.setupMobileMenu();
+    @observable private mainDoc: any = CurrentUserUtils.setupActiveMobile(this.userDoc);
     @observable private renderView?: () => JSX.Element;
     @observable private audioState: any;
     @observable private activeToolbar: boolean = false;
@@ -86,13 +83,7 @@ export class MobileInterface extends React.Component {
 
     @action
     componentDidMount = () => {
-        library.add(...[faPenNib, faHighlighter, faEraser, faMousePointer, faThumbtack]);
-        if (this.userDoc.activeMobile) {
-            console.log(Doc.UserDoc().activeMobile);
-        }
-        if (this.userDoc && !this.mainContainer) {
-            this.userDoc.activeMobile = this._homeDoc;
-        }
+        Doc.UserDoc().activeMobile = this._homeDoc;
         this._homeDoc._viewType === "stacking" ? this.menuListView = true : this.menuListView = false;
         Doc.SetSelectedTool(InkTool.None);
         this.switchCurrentView((userDoc: Doc) => this._homeDoc);
@@ -353,26 +344,6 @@ export class MobileInterface extends React.Component {
                 <div className="hidePath" />
             </div>);
         }
-        //     }
-        // } else {
-
-        //     return (
-        //         <div className="pathbar">
-        //             <div className="scrollmenu">
-        //                 <div className="pathbarItem">
-        //                     <div className="pathbarText"
-        //                         style={{ backgroundColor: "rgb(119, 37, 37)" }}
-        //                         key={0}
-        //                         onClick={() => this.returnHome()}>Home
-        //                     </div>
-        //                 </div>
-        //             </div>
-        //             <div className="hidePath" />
-        //         </div>
-        //     );
-        // }
-
-        // }
     }
 
     // Handles when user clicks on document in the pathbar
@@ -393,16 +364,6 @@ export class MobileInterface extends React.Component {
     }
 
     renderDefaultContent = () => {
-        let menuButtons = DocListCast(this._homeDoc.data).map((doc: Doc, index: any) => {
-            if (doc.type !== "ink") {
-                return (
-                    <div
-                        className="item"
-                        key={index}
-                        onClick={() => doc.onClick}>{doc.title}
-                    </div>);
-            }
-        });
 
         if (this._homeMenu === true) {
             return (
@@ -420,7 +381,10 @@ export class MobileInterface extends React.Component {
                     {this.renderPathbar()}
                     <div className="sidebar" id="sidebar">
                         <div className="sidebarButtons">
-                            {menuButtons}
+                            <div
+                                className="item"
+                                onClick={() => ScriptField.MakeScript("createNewWorkspace()")}>Create New Workspace
+                            </div>
                         </div>
                     </div>
                 </div>
@@ -429,7 +393,7 @@ export class MobileInterface extends React.Component {
 
         let workspaces = Cast(this.userDoc.myWorkspaces, Doc) as Doc;
         if (this._child) {
-            workspaces = this._child
+            workspaces = this._child;
         }
 
         let buttons = DocListCast(workspaces.data).map((doc: Doc, index: any) => {
@@ -468,6 +432,10 @@ export class MobileInterface extends React.Component {
                             </> :
                             <>
                                 {buttons}
+                                <div
+                                    className="item"
+                                    onClick={() => ScriptField.MakeScript("createNewWorkspace()")}>Create New Workspace
+                                </div>
                             </>
                         }
                     </div>
@@ -627,100 +595,12 @@ export class MobileInterface extends React.Component {
         // this.recordAudio();
     }
 
-    // renderActiveCollection = (userDoc: Doc) => {
-    //     if (this.activeContainer) {
-    //         const active = Cast(this.activeContainer.data, listSpec(Doc));
-    //         if (active) {
-    //             return (
-    //                 <div className="mobileInterface-background">HELLO!</div>
-    //             );
-    //         }
-    //     }
-    // }
-
-    onBack = (e: React.MouseEvent) => {
-        this.switchCurrentView((userDoc: Doc) => this.mainDoc);
-        Doc.SetSelectedTool(InkTool.None); // TODO: switch to previous tool
-
-        DocServer.Mobile.dispatchOverlayTrigger({
-            enableOverlay: false,
-            width: window.innerWidth,
-            height: window.innerHeight
-        });
-
-        // this.inkDoc = undefined;
-        this.drawingInk = false;
-    }
-
-    shiftLeft = (e: React.MouseEvent) => {
-        DocServer.Mobile.dispatchOverlayPositionUpdate({
-            dx: -10
-        });
-        e.preventDefault();
-        e.stopPropagation();
-    }
-
-    shiftRight = (e: React.MouseEvent) => {
-        DocServer.Mobile.dispatchOverlayPositionUpdate({
-            dx: 10
-        });
-        e.preventDefault();
-        e.stopPropagation();
-    }
-
     panelHeight = () => window.innerHeight;
     panelWidth = () => window.innerWidth;
     //WAS 3
 
     //WAS 1
 
-    upload = async (e: React.MouseEvent) => {
-        if (this.mainContainer) {
-            const data = Cast(this.mainContainer.data, listSpec(Doc));
-            if (data) {
-                const collectionDoc = await data[1]; //this should be the collection doc since the positions should be locked
-                const children = DocListCast(collectionDoc.data);
-                const uploadDoc = children.length === 1 ? children[0] : Docs.Create.StackingDocument(children, {
-                    title: "Mobile Upload Collection", backgroundColor: "white", lockedPosition: true, _width: 300, _height: 300
-                });
-                if (uploadDoc) {
-                    DocServer.Mobile.dispatchMobileDocumentUpload({
-                        docId: uploadDoc[Id],
-                    });
-                }
-            }
-        }
-        e.stopPropagation();
-        e.preventDefault();
-    }
-
-    addWebToCollection = async () => {
-        let url = "https://en.wikipedia.org/wiki/Hedgehog";
-        if (this.mainContainer) {
-            const data = Cast(this.mainContainer.data, listSpec(Doc));
-            if (data) {
-                const webDoc = await data[0];
-                const urlField: FieldResult<WebField> = Cast(webDoc.data, WebField);
-                url = urlField ? urlField.url.toString() : "https://en.wikipedia.org/wiki/Hedgehog";
-
-            }
-        }
-        Docs.Create.WebDocument(url, { _width: 300, _height: 300, title: "Mobile Upload Web Doc" });
-    }
-
-    clearUpload = async () => {
-        if (this.mainContainer) {
-            const data = Cast(this.mainContainer.data, listSpec(Doc));
-            if (data) {
-                const collectionDoc = await data[1];
-                const children = DocListCast(collectionDoc.data);
-                children.forEach(doc => {
-                });
-                // collectionDoc[data] = new List<Doc>();
-            }
-        }
-    }
-
     pinToPresentation = () => {
         // Only making button available if it is an image
         if (this._activeDoc.type === "image") {
@@ -845,7 +725,6 @@ export class MobileInterface extends React.Component {
                     {this.uploadAudioButton()}
                     {/* {this.colorTool()} */}
                     {this.inkMenu()}
-                    <InkOptionsMenu />
                 </div>
                 <GestureOverlay>
                     {this.displayWorkspaces()}
@@ -879,14 +758,6 @@ export class MobileInterface extends React.Component {
         this.imageUploadActive = false;
     }
 
-    // toggleUpload = () => {
-    //     if (this.imageUploadActive === true) {
-    //         this.imageUploadActive = false;
-    //     } else {
-    //         this.imageUploadActive = true;
-    //     }
-    // }
-
     uploadImage = () => {
         if (this.imageUploadActive) {
             console.log("active");
@@ -905,11 +776,6 @@ export class MobileInterface extends React.Component {
     }
 }
 
-
-
-const inputRef = React.createRef<HTMLInputElement>();
-
-
 Scripting.addGlobal(function switchMobileView(doc: (userDoc: Doc) => Doc, renderView?: () => JSX.Element, onSwitch?: () => void) { return MobileInterface.Instance.switchCurrentView(doc, renderView, onSwitch); });
 Scripting.addGlobal(function openMobilePresentation() { return MobileInterface.Instance.setupDefaultPresentation(); });
 Scripting.addGlobal(function toggleMobileSidebar() { return MobileInterface.Instance.toggleSidebar(); });
diff --git a/src/mobile/MobileMenu.scss b/src/mobile/MobileMenu.scss
index da1e9d951..44d3acb6f 100644
--- a/src/mobile/MobileMenu.scss
+++ b/src/mobile/MobileMenu.scss
@@ -96,7 +96,7 @@ body {
 }
 
 .sidebar {
-    position: absolute;
+    position: fixed;
     top: 120px;
     opacity: 0;
     right: -100%;
@@ -212,7 +212,7 @@ body {
 }
 
 .pathbar {
-    position: absolute;
+    position: fixed;
     top: 118px;
     left: 0px;
     background: #1a1a1a;
@@ -373,7 +373,7 @@ body {
 }
 
 .homeSwitch {
-    position: absolute;
+    position: fixed;
     top: 212;
     right: 36px;
     display: inline-flex;
@@ -401,4 +401,4 @@ body {
 .list.active {
     color: darkred;
     border-color: darkred;
-}
+}
\ No newline at end of file
-- 
cgit v1.2.3-70-g09d2


From 6d68abf588f7b6182a62b74882d1fdc09b2b0230 Mon Sep 17 00:00:00 2001
From: Lionel Han <47760119+IGoByJoe@users.noreply.github.com>
Date: Tue, 16 Jun 2020 09:50:22 -0700
Subject: bug fixes

---
 .../collectionFreeForm/InkOptionsMenu.tsx          |  2 +-
 src/mobile/MobileInterface.tsx                     | 30 ++++------------------
 src/mobile/MobileMenu.scss                         |  3 +++
 3 files changed, 9 insertions(+), 26 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
index 8bebcd047..e7ef4cbd2 100644
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
@@ -107,7 +107,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
                 onPointerDown={action(e => GestureOverlay.Instance.InkShape = btn)}
                 style={{ backgroundColor: btn === GestureOverlay.Instance?.InkShape ? "121212" : "" }}>
                 {this._icons[i]}
-            </button>)},
+            </button>)}
         </>;
     }
 
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 25dc9fd55..5d361f3ab 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -78,6 +78,11 @@ export class MobileInterface extends React.Component {
         document.addEventListener("dblclick", this.onReactDoubleClick);
     }
 
+    @action
+    componentWillUnmount = () => {
+        document.removeEventListener('dblclick', this.onReactDoubleClick);
+    }
+
     // Prevent zooming in when double tapping the screen
     onReactDoubleClick = (e: MouseEvent) => {
         e.stopPropagation();
@@ -94,31 +99,6 @@ export class MobileInterface extends React.Component {
         this.renderView = renderView;
     }
 
-    onSwitchUpload = async () => {
-        let width = 300;
-        let height = 300;
-        const res = await rp.get(Utils.prepend("/getUserDocumentId"));
-
-        // get width and height of the collection doc
-        if (this.mainContainer) {
-            const data = Cast(this.mainContainer.data, listSpec(Doc));
-            if (data) {
-                const collectionDoc = await data[1]; // this should be the collection doc since the positions should be locked
-                const docView = DocumentManager.Instance.getDocumentView(collectionDoc);
-                if (docView) {
-                    width = docView.nativeWidth ? docView.nativeWidth : 300;
-                    height = docView.nativeHeight ? docView.nativeHeight : 300;
-                }
-            }
-        }
-        DocServer.Mobile.dispatchOverlayTrigger({
-            enableOverlay: true,
-            width: width,
-            height: height,
-            text: "Documents uploaded from mobile will show here",
-        });
-    }
-
     // For toggling the hamburger menu
     @action
     toggleSidebar = () => this.sidebarActive = !this.sidebarActive
diff --git a/src/mobile/MobileMenu.scss b/src/mobile/MobileMenu.scss
index 8d996f779..cd531056e 100644
--- a/src/mobile/MobileMenu.scss
+++ b/src/mobile/MobileMenu.scss
@@ -20,6 +20,7 @@ body {
     height: $navbar-height;
     background-color: whitesmoke;
     border-bottom: 5px solid black;
+    z-index: 150;
 }
 
 .navbar .cover {
@@ -192,8 +193,10 @@ body {
 
 
 .sidebar.active {
+    position: absolute;
     right: 0%;
     opacity: 1;
+    z-index: 101;
 }
 
 .back {
-- 
cgit v1.2.3-70-g09d2


From 57d4c562b6f0ef39dcd68f2985a56c4a683fcf49 Mon Sep 17 00:00:00 2001
From: geireann <60007097+geireann@users.noreply.github.com>
Date: Thu, 18 Jun 2020 04:38:08 +0800
Subject: pdf changes + radial menu + create new workspaces

(bug with ink)
---
 src/client/views/GestureOverlay.tsx                |  8 ---
 .../views/collections/CollectionStackingView.tsx   |  2 +-
 .../collectionFreeForm/InkOptionsMenu.tsx          |  4 +-
 src/client/views/nodes/DocumentView.tsx            | 12 ++--
 src/client/views/nodes/PDFBox.scss                 |  2 +-
 src/client/views/nodes/PDFBox.tsx                  |  7 +-
 .../views/nodes/formattedText/FormattedTextBox.tsx |  2 +-
 src/client/views/pdf/PDFViewer.tsx                 |  4 +-
 src/mobile/ImageUpload.tsx                         |  6 +-
 src/mobile/MobileInterface.tsx                     | 80 +++++++++++++++++++---
 src/server/ApiManagers/PDFManager.ts               |  3 +-
 11 files changed, 94 insertions(+), 36 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx')

diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index e51e2d4e1..1c305ebeb 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -575,14 +575,6 @@ export default class GestureOverlay extends Touchable {
             const points = this._points.map(p => ({ X: p.X - B.left, Y: p.Y - B.top }));
             //push first points to so interactionUtil knows pointer is up
             this._points.push({ X: this._points[0].X, Y: this._points[0].Y });
-            if (MobileInterface.Instance && MobileInterface.Instance.drawingInk) {
-                DocServer.Mobile.dispatchGesturePoints({
-                    points: this._points,
-                    bounds: B,
-                    color: ActiveInkColor(),
-                    width: ActiveInkWidth()
-                });
-            }
 
             const initialPoint = this._points[0.];
             const xInGlass = initialPoint.X > (this._thumbX ?? Number.MAX_SAFE_INTEGER) && initialPoint.X < (this._thumbX ?? Number.MAX_SAFE_INTEGER) + (this.height);
diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx
index 797aabf18..9f1b5d63c 100644
--- a/src/client/views/collections/CollectionStackingView.tsx
+++ b/src/client/views/collections/CollectionStackingView.tsx
@@ -476,7 +476,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument)
                         transformOrigin: "top left",
                     }}
                     onScroll={action(e => {
-                        if (!this.props.isSelected() && this.props.renderDepth && window.innerWidth > 1000) e.currentTarget.scrollTop = this._scroll;
+                        if (!this.props.isSelected() && this.props.renderDepth && window.screen.width > 600) e.currentTarget.scrollTop = this._scroll;
                         else this._scroll = e.currentTarget.scrollTop;
                     })}
                     onDrop={this.onExternalDrop.bind(this)}
diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
index 647847b68..676dc10f4 100644
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
@@ -130,13 +130,13 @@ export default class InkOptionsMenu extends AntimodeMenu {
         ];
 
         const mobileButtons = [
-            this.shapeButtons,
+            ...this.shapeButtons,
             this.bezierButton,
             this.widthPicker,
             this.colorPicker,
         ];
 
-        return (window.innerWidth < 1000 ? this.getElement(mobileButtons) : this.getElement(buttons));
+        return (window.screen.width < 600 ? this.getElement(mobileButtons) : this.getElement(buttons));
     }
 }
 Scripting.addGlobal(function activatePen(penBtn: any) {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 75627607b..e027b6a0f 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -31,7 +31,7 @@ import { SelectionManager } from "../../util/SelectionManager";
 import SharingManager from '../../util/SharingManager';
 import { Transform } from "../../util/Transform";
 import { undoBatch, UndoManager } from "../../util/UndoManager";
-import { CollectionDockingView } from "../collections/CollectionDockingView";
+import { CollectionDockingView, DockedFrameRenderer } from "../collections/CollectionDockingView";
 import { CollectionView, CollectionViewType } from '../collections/CollectionView';
 import { ContextMenu } from "../ContextMenu";
 import { ContextMenuProps } from '../ContextMenuItem';
@@ -43,6 +43,7 @@ import "./DocumentView.scss";
 import { LinkAnchorBox } from './LinkAnchorBox';
 import { RadialMenu } from './RadialMenu';
 import React = require("react");
+import { MobileInterface } from '../../../mobile/MobileInterface';
 
 library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight,
     fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale,
@@ -181,10 +182,11 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
         const pt = me.touchEvent.touches[me.touchEvent.touches.length - 1];
         RadialMenu.Instance.openMenu(pt.pageX - 15, pt.pageY - 15);
 
-        RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "map-pin", selected: -1 });
-        RadialMenu.Instance.addItem({ description: "Delete this document", event: () => { this.props.ContainingCollectionView?.removeDocument(this.props.Document), RadialMenu.Instance.closeMenu(); }, icon: "layer-group", selected: -1 });
-        RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, "onRight"), icon: "trash", selected: -1 });
-        RadialMenu.Instance.addItem({ description: "Pin to Presentation", event: () => this.props.pinToPres(this.props.Document), icon: "folder", selected: -1 });
+        // RadialMenu.Instance.addItem({ description: "Open Fields", event: () => this.props.addDocTab(Docs.Create.KVPDocument(this.props.Document, { _width: 300, _height: 300 }), "onRight"), icon: "map-pin", selected: -1 });
+        RadialMenu.Instance.addItem({ description: "Delete", event: () => { this.props.ContainingCollectionView?.removeDocument(this.props.Document), RadialMenu.Instance.closeMenu(); }, icon: "external-link-square-alt", selected: -1 });
+        // RadialMenu.Instance.addItem({ description: "Open in a new tab", event: () => this.props.addDocTab(this.props.Document, "onRight"), icon: "trash", selected: -1 });
+        RadialMenu.Instance.addItem({ description: "Pin", event: () => DockedFrameRenderer.PinDoc(this.props.Document), icon: "map-pin", selected: -1 });
+        RadialMenu.Instance.addItem({ description: "Open", event: () => MobileInterface.Instance.handleClick(this.props.Document), icon: "trash", selected: -1 });
 
         SelectionManager.DeselectAll();
     }
diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss
index 474587159..1a31d2916 100644
--- a/src/client/views/nodes/PDFBox.scss
+++ b/src/client/views/nodes/PDFBox.scss
@@ -224,7 +224,7 @@
     }
 }
 
-@media only screen and (max-width: 1000px) {
+@media only screen and (max-width: 600px) {
 
     .pdfBox .pdfBox-ui .pdfBox-settingsCont .pdfBox-settingsButton,
     .pdfBox-interactive .pdfBox-ui .pdfBox-settingsCont .pdfBox-settingsButton {
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index 78b7faeee..4b4348d3c 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -215,13 +215,14 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
 
     @computed get contentScaling() { return this.props.ContentScaling(); }
     @computed get renderTitleBox() {
-        console.log("fitWidth ?: " + !(this.props.Document._fitWidth) && (window.innerWidth > 1000));
+        console.log("fitWidth ?: " + !(this.props.Document._fitWidth) && (window.screen.width > 600));
         console.log("_nativeHeight: " + this.Document._nativeHeight);
         console.log("%: " + `${100 / this.contentScaling}%`);
         const classname = "pdfBox" + (this.active() ? "-interactive" : "");
         return <div className={classname} style={{
             width: !this.props.Document._fitWidth ? this.Document._nativeWidth || 0 : `${100 / this.contentScaling}%`,
-            height: !this.props.Document._fitWidth && (window.innerWidth > 1000) ? this.Document._nativeHeight || 0 : `${100 / this.contentScaling}%`, //Adjusted for mobile (!window.innerWidth < 1000)
+            //height adjusted for mobile (window.screen.width > 600)
+            height: !this.props.Document._fitWidth && (window.screen.width > 600) ? this.Document._nativeHeight || 0 : `${100 / this.contentScaling}%`,
             transform: `scale(${this.contentScaling})`
         }}  >
             <div className="pdfBox-title-outer">
@@ -233,7 +234,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<FieldViewProps, PdfDocum
     isChildActive = (outsideReaction?: boolean) => this._isChildActive;
     @computed get renderPdfView() {
         const pdfUrl = Cast(this.dataDoc[this.props.fieldKey], PdfField);
-        return <div className={"pdfBox"} onContextMenu={this.specificContextMenu} style={{ height: this.props.Document._scrollTop && !this.Document._fitWidth && (window.innerWidth > 1000) ? NumCast(this.Document._height) * this.props.PanelWidth() / NumCast(this.Document._width) : undefined }}>
+        return <div className={"pdfBox"} onContextMenu={this.specificContextMenu} style={{ height: this.props.Document._scrollTop && !this.Document._fitWidth && (window.screen.width > 600) ? NumCast(this.Document._height) * this.props.PanelWidth() / NumCast(this.Document._width) : undefined }}>
             <PDFViewer {...this.props} pdf={this._pdf!} url={pdfUrl!.url.pathname} active={this.props.active} loaded={this.loaded}
                 setPdfViewer={this.setPdfViewer} ContainingCollectionView={this.props.ContainingCollectionView}
                 renderDepth={this.props.renderDepth} PanelHeight={this.props.PanelHeight} PanelWidth={this.props.PanelWidth}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index f3d0d135c..ae508cd67 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -261,7 +261,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
     }
 
     public unhighlightSearchTerms = () => {
-        if (window.innerWidth < 1000) null;
+        if (window.screen.width < 600) null;
         else if (this._editorView && (this._editorView as any).docView) {
             const mark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight);
             const activeMark = this._editorView.state.schema.mark(this._editorView.state.schema.marks.search_highlight, { selected: true });
diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx
index 9cdbea2da..57b7bceca 100644
--- a/src/client/views/pdf/PDFViewer.tsx
+++ b/src/client/views/pdf/PDFViewer.tsx
@@ -709,8 +709,8 @@ export class PDFViewer extends ViewBoxAnnotatableComponent<IViewerProps, PdfDocu
             onScroll={this.onScroll} onWheel={this.onZoomWheel} onPointerDown={this.onPointerDown} onClick={this.onClick}
             style={{
                 overflowX: this._zoomed !== 1 ? "scroll" : undefined,
-                width: !this.props.Document._fitWidth && (window.innerWidth > 1000) ? NumCast(this.props.Document._nativeWidth) : `${100 / this.contentScaling}%`,
-                height: !this.props.Document._fitWidth && (window.innerWidth > 1000) ? NumCast(this.props.Document._nativeHeight) : `${100 / this.contentScaling}%`,
+                width: !this.props.Document._fitWidth && (window.screen.width > 600) ? NumCast(this.props.Document._nativeWidth) : `${100 / this.contentScaling}%`,
+                height: !this.props.Document._fitWidth && (window.screen.width > 600) ? NumCast(this.props.Document._nativeHeight) : `${100 / this.contentScaling}%`,
                 transform: `scale(${this.props.ContentScaling()})`
             }}  >
             {this.pdfViewerDiv}
diff --git a/src/mobile/ImageUpload.tsx b/src/mobile/ImageUpload.tsx
index d8b1913ee..b66f0461d 100644
--- a/src/mobile/ImageUpload.tsx
+++ b/src/mobile/ImageUpload.tsx
@@ -65,8 +65,11 @@ export class Uploader extends React.Component {
                             }
                             const path = Utils.prepend(result.accessPaths.agnostic.client);
                             let doc = null;
+                            console.log("type: " + file.type);
                             if (file.type === "video/mp4") {
                                 doc = Docs.Create.VideoDocument(path, { _nativeWidth: 200, _width: 200, title: name });
+                            } else if (file.type === "application/pdf") {
+                                doc = Docs.Create.PdfDocument(path, { _width: 200, title: name });
                             } else {
                                 doc = Docs.Create.ImageDocument(path, { _nativeWidth: 200, _width: 200, title: name });
                             }
@@ -175,7 +178,7 @@ export class Uploader extends React.Component {
     private get uploadInterface() {
         return (
             <div className="imgupload_cont">
-                <input type="file" accept="video/*,image/*" className="inputFile" id="input_image_file" ref={inputRef} onChange={this.inputLabel} multiple></input>
+                <input type="file" accept="application/pdf, video/*,image/*" className="inputFile" id="input_image_file" ref={inputRef} onChange={this.inputLabel} multiple></input>
                 <label className="file" id="label" htmlFor="input_image_file">{this.nm}</label>
                 <div className="upload_label" onClick={this.onClick}>
                     <FontAwesomeIcon icon="upload" size="sm" />
@@ -217,4 +220,3 @@ export class Uploader extends React.Component {
 }
 
 
-// DocServer.init(window.location.protocol, window.location.hostname, 4321, "image upload");
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 5acdc1dea..644535179 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -1,7 +1,7 @@
 import * as React from "react";
 import { library } from '@fortawesome/fontawesome-svg-core';
 import {
-    faTasks, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus,
+    faTasks, faExternalLinkSquareAlt, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus,
     faTerminal, faToggleOn, faFile as fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard,
     faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt,
     faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter,
@@ -17,7 +17,7 @@ import { FieldValue, Cast } from '../fields/Types';
 import { CurrentUserUtils } from '../client/util/CurrentUserUtils';
 import { emptyPath, emptyFunction, returnFalse, returnOne, returnTrue, returnZero, Utils } from '../Utils';
 import { DocServer } from '../client/DocServer';
-import { Docs } from '../client/documents/Documents';
+import { Docs, DocumentOptions } from '../client/documents/Documents';
 import { Scripting } from '../client/util/Scripting';
 import { DocumentView } from '../client/views/nodes/DocumentView';
 import { Transform } from '../client/util/Transform';
@@ -36,8 +36,11 @@ import GestureOverlay from "../client/views/GestureOverlay";
 import { ScriptField } from "../fields/ScriptField";
 import InkOptionsMenu from "../client/views/collections/collectionFreeForm/InkOptionsMenu";
 import { RadialMenu } from "../client/views/nodes/RadialMenu";
+import { UndoManager } from "../client/util/UndoManager";
+import { MainView } from "../client/views/MainView";
+import { List } from "../fields/List";
 
-library.add(faTasks, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus,
+library.add(faTasks, faExternalLinkSquareAlt, faMobile, faThLarge, faWindowClose, faEdit, faTrashAlt, faPalette, faAngleRight, faBell, faTrash, faCamera, faExpand, faCaretDown, faCaretLeft, faCaretRight, faCaretSquareDown, faCaretSquareRight, faArrowsAltH, faPlus, faMinus,
     faTerminal, faToggleOn, fileSolid, faExternalLinkAlt, faLocationArrow, faSearch, faFileDownload, faStop, faCalculator, faWindowMaximize, faAddressCard,
     faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt,
     faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter,
@@ -149,7 +152,7 @@ export class MobileInterface extends React.Component {
      * Return 'Home", which implies returning to 'Home' buttons
      */
     returnHome = () => {
-        if (this._homeMenu === false || this.sidebarActive === true) {
+        if (this._homeMenu || this.sidebarActive) {
             this._homeMenu = true;
             this._parents = [];
             this._activeDoc = this._homeDoc;
@@ -220,7 +223,7 @@ export class MobileInterface extends React.Component {
      */
     handleClick = async (doc: Doc) => {
         const children = DocListCast(doc.data);
-        if (doc.type !== "collection") {
+        if (doc.type !== "collection" && this.sidebarActive) {
             this._parents.push(this._activeDoc);
             this._activeDoc = doc;
             this.switchCurrentView((userDoc: Doc) => doc);
@@ -333,7 +336,7 @@ export class MobileInterface extends React.Component {
 
     // Renders the contents of the menu and sidebar
     renderDefaultContent = () => {
-        if (this._homeMenu === true) {
+        if (this._homeMenu) {
             return (
                 <div>
                     <div className="navbar">
@@ -351,7 +354,7 @@ export class MobileInterface extends React.Component {
                         <div className="sidebarButtons">
                             <div
                                 className="item"
-                                onClick={() => ScriptField.MakeScript("createNewWorkspace()")}>Create New Workspace
+                                onClick={() => MainView.Instance?.createNewWorkspace()}>Create New Workspace
                             </div>
                         </div>
                     </div>
@@ -403,7 +406,10 @@ export class MobileInterface extends React.Component {
                                 {buttons}
                                 <div
                                     className="item"
-                                    onClick={() => ScriptField.MakeScript("createNewWorkspace()")}>Create New Workspace
+                                    style={{ opacity: 0.7 }}
+                                    onClick={() => this.createNewWorkspace()}>
+                                    <FontAwesomeIcon className="right" icon="plus" size="lg" />
+                                    <div className="item-type">Create New Workspace</div>
                                 </div>
                             </>
                         }
@@ -413,6 +419,32 @@ export class MobileInterface extends React.Component {
         );
     }
 
+    /**
+     * Handles the Create New Workspace button in the menu
+     */
+    @action
+    createNewWorkspace = async (id?: string) => {
+        const workspaces = Cast(this.userDoc.myWorkspaces, Doc) as Doc;
+        const workspaceCount = DocListCast(workspaces.data).length + 1;
+        const freeformOptions: DocumentOptions = {
+            x: 0,
+            y: 400,
+            title: "Collection " + workspaceCount,
+            _LODdisable: true
+        };
+        const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions);
+        const workspaceDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().myCatalog as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row");
+
+        const toggleTheme = ScriptField.MakeScript(`self.darkScheme = !self.darkScheme`);
+        const toggleComic = ScriptField.MakeScript(`toggleComicMode()`);
+        const cloneWorkspace = ScriptField.MakeScript(`cloneWorkspace()`);
+        workspaceDoc.contextMenuScripts = new List<ScriptField>([toggleTheme!, toggleComic!, cloneWorkspace!]);
+        workspaceDoc.contextMenuLabels = new List<string>(["Toggle Theme Colors", "Toggle Comic Mode", "New Workspace Layout"]);
+
+        Doc.AddDocToList(workspaces, "data", workspaceDoc);
+        // bcz: strangely, we need a timeout to prevent exceptions/issues initializing GoldenLayout (the rendering engine for Main Container)
+    }
+
     stop = (e: React.MouseEvent) => {
         e.stopPropagation();
     }
@@ -431,7 +463,7 @@ export class MobileInterface extends React.Component {
         }
     }
 
-    // Button for switching between pan and ink mode
+    // Button for switching between pen and ink mode
     @action
     onSwitchInking = () => {
         const button = document.getElementById("inkButton") as HTMLElement;
@@ -465,6 +497,16 @@ export class MobileInterface extends React.Component {
         if (this._activeDoc._viewType === "docking") {
             return (
                 <>
+                    {/* <div className="docButton"
+                        id="undoButton"
+                        title="undo"
+                        onClick={(e: React.MouseEvent) => {
+                            UndoManager.Undo();
+                            e.stopPropagation();
+                        }}>
+                        <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="undo-alt"
+                        />
+                    </div> */}
                     <div className="docButton"
                         id="inkButton"
                         title={Doc.isDocPinned(this._activeDoc) ? "Pen on" : "Pen off"}
@@ -472,6 +514,16 @@ export class MobileInterface extends React.Component {
                         <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="pen-nib"
                         />
                     </div>
+                    {/* <div className="docButton"
+                        id="redoButton"
+                        title="redo"
+                        onClick={(e: React.MouseEvent) => {
+                            UndoManager.Redo();
+                            e.stopPropagation();
+                        }}>
+                        <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="redo-alt"
+                        />
+                    </div> */}
                 </>);
         }
     }
@@ -645,6 +697,12 @@ export class MobileInterface extends React.Component {
         );
     }
 
+    displayRadialMenu = () => {
+        if (this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc) {
+            return <RadialMenu />;
+        }
+    }
+
     onDragOver = (e: React.DragEvent) => {
         e.preventDefault();
         e.stopPropagation();
@@ -669,12 +727,14 @@ export class MobileInterface extends React.Component {
                     {this.displayWorkspaces()}
                     {this.renderDefaultContent()}
                 </GestureOverlay>
-                <RadialMenu />
+                {this.displayRadialMenu()}
             </div>
         );
     }
 }
 
+
+
 Scripting.addGlobal(function switchMobileView(doc: (userDoc: Doc) => Doc, renderView?: () => JSX.Element, onSwitch?: () => void) { return MobileInterface.Instance.switchCurrentView(doc, renderView, onSwitch); });
 Scripting.addGlobal(function openMobilePresentation() { return MobileInterface.Instance.setupDefaultPresentation(); });
 Scripting.addGlobal(function toggleMobileSidebar() { return MobileInterface.Instance.toggleSidebar(); });
diff --git a/src/server/ApiManagers/PDFManager.ts b/src/server/ApiManagers/PDFManager.ts
index d2a9e9cce..b0b5a484a 100644
--- a/src/server/ApiManagers/PDFManager.ts
+++ b/src/server/ApiManagers/PDFManager.ts
@@ -55,7 +55,8 @@ async function CreateThumbnail(coreFilename: string, pageNum: number, res: expre
     const documentProxy = await Pdfjs.getDocument(sourcePath).promise;
     const factory = new NodeCanvasFactory();
     const page = await documentProxy.getPage(pageNum);
-    const viewport = page.getViewport(1 as any);
+    const scale = 1;
+    const viewport = page.getViewport(scale as any);
     const { canvas, context } = factory.create(viewport.width, viewport.height);
     const renderContext = {
         canvasContext: context,
-- 
cgit v1.2.3-70-g09d2


From 639be55eaff422e1e982cf41d09edd9e96f014a4 Mon Sep 17 00:00:00 2001
From: yunahi <60233430+yunahi@users.noreply.github.com>
Date: Thu, 18 Jun 2020 14:10:34 +0900
Subject: updated menu

---
 package-lock.json                                  |  44 +++--
 src/client/documents/Documents.ts                  |  10 +-
 src/client/util/CurrentUserUtils.ts                |   4 +
 src/client/util/InteractionUtils.tsx               |  64 +++++--
 src/client/views/DocumentDecorations.scss          |  50 +++--
 src/client/views/DocumentDecorations.tsx           |  81 +++++++-
 src/client/views/GestureOverlay.tsx                |  21 ++-
 src/client/views/InkingStroke.tsx                  |  41 ++++-
 .../collectionFreeForm/CollectionFreeFormView.tsx  |   4 +-
 .../collectionFreeForm/InkOptionsMenu.tsx          | 203 +++++++++++++++++++--
 src/fields/InkField.ts                             |   4 +-
 11 files changed, 459 insertions(+), 67 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx')

diff --git a/package-lock.json b/package-lock.json
index c956fd3e9..cd80ecc5e 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2832,7 +2832,8 @@
                         },
                         "ansi-regex": {
                             "version": "2.1.1",
-                            "bundled": true
+                            "bundled": true,
+                            "optional": true
                         },
                         "aproba": {
                             "version": "1.2.0",
@@ -2850,11 +2851,13 @@
                         },
                         "balanced-match": {
                             "version": "1.0.0",
-                            "bundled": true
+                            "bundled": true,
+                            "optional": true
                         },
                         "brace-expansion": {
                             "version": "1.1.11",
                             "bundled": true,
+                            "optional": true,
                             "requires": {
                                 "balanced-match": "^1.0.0",
                                 "concat-map": "0.0.1"
@@ -2867,15 +2870,18 @@
                         },
                         "code-point-at": {
                             "version": "1.1.0",
-                            "bundled": true
+                            "bundled": true,
+                            "optional": true
                         },
                         "concat-map": {
                             "version": "0.0.1",
-                            "bundled": true
+                            "bundled": true,
+                            "optional": true
                         },
                         "console-control-strings": {
                             "version": "1.1.0",
-                            "bundled": true
+                            "bundled": true,
+                            "optional": true
                         },
                         "core-util-is": {
                             "version": "1.0.2",
@@ -2978,7 +2984,8 @@
                         },
                         "inherits": {
                             "version": "2.0.4",
-                            "bundled": true
+                            "bundled": true,
+                            "optional": true
                         },
                         "ini": {
                             "version": "1.3.5",
@@ -2988,6 +2995,7 @@
                         "is-fullwidth-code-point": {
                             "version": "1.0.0",
                             "bundled": true,
+                            "optional": true,
                             "requires": {
                                 "number-is-nan": "^1.0.0"
                             }
@@ -3000,17 +3008,20 @@
                         "minimatch": {
                             "version": "3.0.4",
                             "bundled": true,
+                            "optional": true,
                             "requires": {
                                 "brace-expansion": "^1.1.7"
                             }
                         },
                         "minimist": {
                             "version": "1.2.5",
-                            "bundled": true
+                            "bundled": true,
+                            "optional": true
                         },
                         "minipass": {
                             "version": "2.9.0",
                             "bundled": true,
+                            "optional": true,
                             "requires": {
                                 "safe-buffer": "^5.1.2",
                                 "yallist": "^3.0.0"
@@ -3027,6 +3038,7 @@
                         "mkdirp": {
                             "version": "0.5.3",
                             "bundled": true,
+                            "optional": true,
                             "requires": {
                                 "minimist": "^1.2.5"
                             }
@@ -3082,7 +3094,8 @@
                         },
                         "npm-normalize-package-bin": {
                             "version": "1.0.1",
-                            "bundled": true
+                            "bundled": true,
+                            "optional": true
                         },
                         "npm-packlist": {
                             "version": "1.4.8",
@@ -3107,7 +3120,8 @@
                         },
                         "number-is-nan": {
                             "version": "1.0.1",
-                            "bundled": true
+                            "bundled": true,
+                            "optional": true
                         },
                         "object-assign": {
                             "version": "4.1.1",
@@ -3117,6 +3131,7 @@
                         "once": {
                             "version": "1.4.0",
                             "bundled": true,
+                            "optional": true,
                             "requires": {
                                 "wrappy": "1"
                             }
@@ -3185,7 +3200,8 @@
                         },
                         "safe-buffer": {
                             "version": "5.1.2",
-                            "bundled": true
+                            "bundled": true,
+                            "optional": true
                         },
                         "safer-buffer": {
                             "version": "2.1.2",
@@ -3215,6 +3231,7 @@
                         "string-width": {
                             "version": "1.0.2",
                             "bundled": true,
+                            "optional": true,
                             "requires": {
                                 "code-point-at": "^1.0.0",
                                 "is-fullwidth-code-point": "^1.0.0",
@@ -3232,6 +3249,7 @@
                         "strip-ansi": {
                             "version": "3.0.1",
                             "bundled": true,
+                            "optional": true,
                             "requires": {
                                 "ansi-regex": "^2.0.0"
                             }
@@ -3270,11 +3288,13 @@
                         },
                         "wrappy": {
                             "version": "1.0.2",
-                            "bundled": true
+                            "bundled": true,
+                            "optional": true
                         },
                         "yallist": {
                             "version": "3.1.1",
-                            "bundled": true
+                            "bundled": true,
+                            "optional": true
                         }
                     }
                 }
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index 8d867348f..cbf97e8e8 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -37,7 +37,7 @@ import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo";
 import { QueryBox } from "../views/nodes/QueryBox";
 import { ColorBox } from "../views/nodes/ColorBox";
 import { DocHolderBox } from "../views/nodes/DocHolderBox";
-import { InkingStroke, ActiveInkColor, ActiveInkWidth, ActiveInkBezierApprox } from "../views/InkingStroke";
+import { InkingStroke, ActiveInkColor, ActiveInkWidth, ActiveInkBezierApprox, ActiveFillColor, ActiveArrowStart, ActiveArrowEnd, ActiveDash } from "../views/InkingStroke";
 import { InkField } from "../../fields/InkField";
 import { RichTextField } from "../../fields/RichTextField";
 import { extname } from "path";
@@ -631,13 +631,17 @@ export namespace Docs {
             return doc;
         }
 
-        export function InkDocument(color: string, tool: string, strokeWidth: string, strokeBezier: string, points: { X: number, Y: number }[], options: DocumentOptions = {}) {
+        export function InkDocument(color: string, tool: string, strokeWidth: string, strokeBezier: string, fillColor: string, arrowStart: string, arrowEnd: string, dash: string, points: { X: number, Y: number }[], options: DocumentOptions = {}) {
             const I = new Doc();
             I.type = DocumentType.INK;
             I.layout = InkingStroke.LayoutString("data");
             I.color = color;
             I.strokeWidth = strokeWidth;
             I.strokeBezier = strokeBezier;
+            I.fillColor = fillColor;
+            I.arrowStart = arrowStart;
+            I.arrowEnd = arrowEnd;
+            I.dash = dash;
             I.tool = tool;
             I.title = "ink";
             I.x = options.x;
@@ -852,7 +856,7 @@ export namespace DocUtils {
             created = Docs.Create.AudioDocument((field).url.href, resolved);
             layout = AudioBox.LayoutString;
         } else if (field instanceof InkField) {
-            created = Docs.Create.InkDocument(ActiveInkColor(), Doc.GetSelectedTool(), ActiveInkWidth(), ActiveInkBezierApprox(), (field).inkData, resolved);
+            created = Docs.Create.InkDocument(ActiveInkColor(), Doc.GetSelectedTool(), ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), (field).inkData, resolved);
             layout = InkingStroke.LayoutString;
         } else if (field instanceof List && field[0] instanceof Doc) {
             created = Docs.Create.StackingDocument(DocListCast(field), resolved);
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index b0cea9947..3d0c0ef4a 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -691,6 +691,10 @@ export class CurrentUserUtils {
         doc.activeInkColor = StrCast(doc.activeInkColor, "rgb(0, 0, 0)");
         doc.activeInkWidth = StrCast(doc.activeInkWidth, "1");
         doc.activeInkBezier = StrCast(doc.activeInkBezier, "");
+        doc.activeFillColor = StrCast(doc.activeFillColor, "none");
+        doc.activeArrowStart = StrCast(doc.activeArrowStart, "none");
+        doc.activeArrowEnd = StrCast(doc.activeArrowEnd, "none");
+        doc.activeDash = StrCast(doc.activeDash, "0");
         doc.fontSize = NumCast(doc.fontSize, 12);
         doc["constants-snapThreshold"] = NumCast(doc["constants-snapThreshold"], 10); // 
         doc["constants-dragThreshold"] = NumCast(doc["constants-dragThreshold"], 4); // 
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index 81f9b9362..c6b96df45 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -1,6 +1,7 @@
 import React = require("react");
 import * as beziercurve from 'bezier-curve';
 import * as fitCurve from 'fit-curve';
+import InkOptionsMenu from "../views/collections/collectionFreeForm/InkOptionsMenu";
 
 export namespace InteractionUtils {
     export const MOUSETYPE = "mouse";
@@ -89,7 +90,8 @@ export namespace InteractionUtils {
         return myTouches;
     }
 
-    export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number, color: string, width: string, bezier: string, scalex: number, scaley: number, shape: string, pevents: string, drawHalo: boolean) {
+
+    export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number, color: string, width: string, bezier: string, fill: string, arrowStart: string, arrowEnd: string, dash: string, scalex: number, scaley: number, shape: string, pevents: string, drawHalo: boolean) {
         var pts = "";
         if (shape) {
             //if any of the shape are true
@@ -116,22 +118,58 @@ export namespace InteractionUtils {
             //in the middle of drawing
             pts = points.reduce((acc: string, pt: { X: number, Y: number }) => acc + `${pt.X * scalex - left * scalex},${pt.Y * scaley - top * scaley} `, "");
         }
+        const dashArray = String(Number(width) * Number(dash));
+
         return (
-            <polyline
-                points={pts}
-                style={{
-                    filter: drawHalo ? "url(#dangerShine)" : undefined,
-                    fill: "none",
-                    pointerEvents: pevents as any,
-                    stroke: color ?? "rgb(0, 0, 0)",
-                    strokeWidth: parseInt(width),
-                    strokeLinejoin: "round",
-                    strokeLinecap: "round"
-                }}
-            />
+            <svg>
+                <defs>
+
+                    {/* {makeArrow()} */}
+                    <marker id="dot" orient="auto" overflow="visible">
+                        <circle r={1} fill="red" />
+                    </marker>
+                    <marker id="arrowHead" orient="auto" overflow="visible" refX="3" refY="1" markerWidth="10" markerHeight="7">
+                        {/* <rect width={strokeWidth} height={strokeWidth} transform='rotate(45)' fill="dodgerblue" /> */}
+                        <polygon points="3 0, 3 2, 0 1" fill="dodgerblue" />
+                    </marker>
+                    <marker id="arrowEnd" orient="auto" overflow="visible" refX="0" refY="1" markerWidth="10" markerHeight="7">
+                        {/* <rect width={strokeWidth} height={strokeWidth} transform='rotate(45)' fill="dodgerblue" /> */}
+                        <polygon points="0 0, 3 1, 0 2" fill={"#" + color} />
+                    </marker>
+                </defs>
+
+                <polyline
+                    points={pts}
+                    style={{
+                        filter: drawHalo ? "url(#dangerShine)" : undefined,
+                        fill: fill,
+                        pointerEvents: pevents as any,
+                        stroke: color ?? "rgb(0, 0, 0)",
+                        strokeWidth: parseInt(width),
+                        strokeLinejoin: "round",
+                        strokeLinecap: "round",
+                        strokeDasharray: dashArray
+                    }}
+                    markerStart={arrowStart}
+                    markerEnd={arrowEnd}
+                />
+            </svg>
+
         );
     }
 
+    // export function makeArrow() {
+    //     return (
+    //         InkOptionsMenu.Instance.getColors().map(color => {
+    //             const id1 = "arrowHeadTest" + color;
+    //             console.log(color);
+    //             <marker id={id1} orient="auto" overflow="visible" refX="0" refY="1" markerWidth="10" markerHeight="7">
+    //                 <polygon points="0 0, 3 1, 0 2" fill={"#" + color} />
+    //             </marker>;
+    //         })
+    //     );
+    // }
+
     export function makePolygon(shape: string, points: { X: number, Y: number }[]) {
         if (points.length > 1 && points[points.length - 1].X === points[0].X && points[points.length - 1].Y + 1 === points[0].Y) {
             //pointer is up (first and last points are the same)
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index 0a96b058b..cf5871bda 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -22,11 +22,20 @@ $linkGap : 3px;
     }
 
 
+    .documentDecorations-rotation {
+        pointer-events: auto;
+        // cursor: grabbing;
+        cursor: ns-resize;
+        width: 10px;
+        height: 10px;
+    }
+
     .documentDecorations-resizer {
         pointer-events: auto;
         background: $alt-accent;
         opacity: 0.1;
     }
+
     .documentDecorations-resizer:hover {
         opacity: 1;
     }
@@ -87,14 +96,17 @@ $linkGap : 3px;
         background: unset;
         opacity: 1;
     }
+
     #documentDecorations-topLeftResizer {
-        border-left:  2px solid;
-        border-top:  solid 2px;
+        border-left: 2px solid;
+        border-top: solid 2px;
     }
+
     #documentDecorations-bottomRightResizer {
-        border-right:  2px solid;
-        border-bottom:  solid 2px;
+        border-right: 2px solid;
+        border-bottom: solid 2px;
     }
+
     #documentDecorations-topLeftResizer:hover,
     #documentDecorations-bottomRightResizer:hover {
         opacity: 1;
@@ -110,14 +122,17 @@ $linkGap : 3px;
         background: unset;
         opacity: 1;
     }
+
     #documentDecorations-topRightResizer {
-        border-right:  2px solid;
-        border-top:  2px solid;
+        border-right: 2px solid;
+        border-top: 2px solid;
     }
+
     #documentDecorations-bottomLeftResizer {
-        border-left:  2px solid;
-        border-bottom:  2px solid;
+        border-left: 2px solid;
+        border-bottom: 2px solid;
     }
+
     #documentDecorations-topRightResizer:hover,
     #documentDecorations-bottomLeftResizer:hover {
         cursor: nesw-resize;
@@ -139,10 +154,11 @@ $linkGap : 3px;
         width: 25px;
         height: calc(100% + 8px); // 8px for the height of the top resizer bar
         grid-column-start: 2;
-        grid-column-end : 2;
+        grid-column-end: 2;
         pointer-events: all;
         padding-left: 5px;
     }
+
     .documentDecorations-title {
         opacity: 1;
         grid-column-start: 3;
@@ -150,14 +166,16 @@ $linkGap : 3px;
         pointer-events: auto;
         overflow: hidden;
         text-align: center;
-        display: flex;    
+        display: flex;
         border-bottom: solid 1px;
-        margin-left:10px;
+        margin-left: 10px;
         width: calc(100% - 10px);
     }
+
     .focus-visible {
-        margin-left:0px;
+        margin-left: 0px;
     }
+
     .publishBox {
         width: 20px;
         height: 22px;
@@ -194,8 +212,9 @@ $linkGap : 3px;
     width: 8px;
     height: $MINIMIZED_ICON_SIZE;
     max-height: 20px;
-    > svg {
-        margin:0;
+
+    >svg {
+        margin: 0;
     }
 }
 
@@ -332,7 +351,8 @@ $linkGap : 3px;
     padding: 2px 12px;
     list-style: none;
 
-    .templateToggle, .chromeToggle {
+    .templateToggle,
+    .chromeToggle {
         text-align: left;
     }
 
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 6ca7331d6..8cb0c83ed 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -17,11 +17,13 @@ import { DocumentButtonBar } from './DocumentButtonBar';
 import './DocumentDecorations.scss';
 import { DocumentView } from "./nodes/DocumentView";
 import React = require("react");
-import { Id } from '../../fields/FieldSymbols';
+import { Id, Copy, Update } from '../../fields/FieldSymbols';
 import e = require('express');
 import { CollectionDockingView } from './collections/CollectionDockingView';
 import { SnappingManager } from '../util/SnappingManager';
 import { HtmlField } from '../../fields/HtmlField';
+import { InkData, InkField, InkTool } from "../../fields/InkField";
+import { update } from 'serializr';
 
 library.add(faCaretUp);
 library.add(faObjectGroup);
@@ -50,6 +52,10 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
     private _resizeUndo?: UndoManager.Batch;
     private _offX = 0; _offY = 0;  // offset from click pt to inner edge of resize border
     private _snapX = 0; _snapY = 0; // last snapped location of resize border
+    private _prevX = 0;
+    private _prevY = 0;
+    private _centerPoints: { X: number, Y: number }[] = [];
+
     @observable private _accumulatedTitle = "";
     @observable private _titleControlString: string = "#title";
     @observable private _edtingTitle = false;
@@ -237,6 +243,77 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
         return false;
     }
 
+    @action
+    onRotateDown = (e: React.PointerEvent): void => {
+        setupMoveUpEvents(this, e, this.onRotateMove, this.onRotateUp, (e) => { });
+        this._prevX = e.clientX;
+        this._prevY = e.clientY;
+        SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) => {
+            const doc = Document(element.rootDoc);
+            if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
+                const ink = Cast(doc.data, InkField)?.inkData;
+                if (ink) {
+                    const xs = ink.map(p => p.X);
+                    const ys = ink.map(p => p.Y);
+                    const left = Math.min(...xs);
+                    const top = Math.min(...ys);
+                    const right = Math.max(...xs);
+                    const bottom = Math.max(...ys);
+                    this._centerPoints.push({ X: ((right - left) / 2) + left, Y: ((bottom - top) / 2) + bottom });
+                }
+            }
+        }));
+
+    }
+    @action
+    onRotateMove = (e: PointerEvent, down: number[]): boolean => {
+        // const distance = Math.sqrt((this._prevY - e.clientY) * (this._prevY - e.clientY) + (this._prevX - e.clientX) * (this._prevX - e.clientX));
+        const distance = Math.abs(this._prevY - e.clientY);
+        var angle = 0;
+        //think of a better condition later...
+        // if ((down[0] < e.clientX && this._prevY < e.clientY) || (down[0] > e.clientX && this._prevY > e.clientY)) {
+        if (e.clientY > this._prevY) {
+            angle = distance * (Math.PI / 180);
+            // } else if ((down[0] < e.clientX && this._prevY > e.clientY) || (down[0] > e.clientX && this._prevY <= e.clientY)) {
+        } else if (e.clientY < this._prevY) {
+            angle = - distance * (Math.PI / 180);
+        }
+        this._prevX = e.clientX;
+        this._prevY = e.clientY;
+        var index = 0;
+        SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) => {
+            const doc = Document(element.rootDoc);
+            if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) {
+                const ink = Cast(doc.data, InkField)?.inkData;
+                if (ink) {
+                    const newPoints: { X: number, Y: number }[] = [];
+                    for (var i = 0; i < ink.length; i++) {
+                        const newX = Math.cos(angle) * (ink[i].X - this._centerPoints[index].X) - Math.sin(angle) * (ink[i].Y - this._centerPoints[index].Y) + this._centerPoints[index].X;
+                        const newY = Math.sin(angle) * (ink[i].X - this._centerPoints[index].X) + Math.cos(angle) * (ink[i].Y - this._centerPoints[index].Y) + this._centerPoints[index].Y;
+                        newPoints.push({ X: newX, Y: newY });
+                    }
+                    doc.data = new InkField(newPoints);
+                    const xs = newPoints.map(p => p.X);
+                    const ys = newPoints.map(p => p.Y);
+                    const left = Math.min(...xs);
+                    const top = Math.min(...ys);
+                    const right = Math.max(...xs);
+                    const bottom = Math.max(...ys);
+                    doc._height = bottom - top;
+                    doc._width = right - left;
+                }
+                index++;
+            }
+        }));
+        return false;
+    }
+
+    onRotateUp = (e: PointerEvent) => {
+        this._centerPoints = [];
+    }
+
+
+
     _initialAutoHeight = false;
     _dragHeights = new Map<Doc, number>();
     @action
@@ -521,6 +598,8 @@ export class DocumentDecorations extends React.Component<{}, { value: string }>
                 <div className="documentDecorations-closeButton" title="Open Document in Tab" onPointerDown={this.onMaximizeDown}>
                     {SelectionManager.SelectedDocuments().length === 1 ? DocumentDecorations.DocumentIcon(StrCast(seldoc.props.Document.layout, "...")) : "..."}
                 </div>
+                <div id="documentDecorations-rotation" className="documentDecorations-rotation"
+                    onPointerDown={this.onRotateDown}> ⟲ </div>
                 <div id="documentDecorations-topLeftResizer" className="documentDecorations-resizer"
                     onPointerDown={this.onPointerDown} onContextMenu={(e) => e.preventDefault()}></div>
                 <div id="documentDecorations-topResizer" className="documentDecorations-resizer"
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index d239a1d6f..5b6cbc372 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -18,7 +18,7 @@ import { LinkManager } from "../util/LinkManager";
 import { Scripting } from "../util/Scripting";
 import { Transform } from "../util/Transform";
 import "./GestureOverlay.scss";
-import { ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from "./InkingStroke";
+import { ActiveInkBezierApprox, ActiveArrowStart, ActiveArrowEnd, ActiveFillColor, ActiveInkColor, ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth, SetActiveFillColor, SetActiveArrowStart, SetActiveArrowEnd, ActiveDash, SetActiveDash } from "./InkingStroke";
 import { DocumentView } from "./nodes/DocumentView";
 import { RadialMenu } from "./nodes/RadialMenu";
 import HorizontalPalette from "./Palette";
@@ -32,6 +32,10 @@ export default class GestureOverlay extends Touchable {
     @observable public InkShape: string = "";
     @observable public SavedColor?: string;
     @observable public SavedWidth?: string;
+    @observable public SavedFill?: string;
+    @observable public SavedArrowStart: string = "none";
+    @observable public SavedArrowEnd: string = "none";
+    @observable public SavedDash: String = "0";
     @observable public Tool: ToolglassTools = ToolglassTools.None;
 
     @observable private _thumbX?: number;
@@ -802,6 +806,7 @@ export default class GestureOverlay extends Touchable {
     }
 
     @computed get elements() {
+
         const B = this.svgBounds;
         return [
             this.props.children,
@@ -809,11 +814,11 @@ export default class GestureOverlay extends Touchable {
             [this._strokes.map(l => {
                 const b = this.getBounds(l);
                 return <svg key={b.left} width={b.width} height={b.height} style={{ transform: `translate(${b.left}px, ${b.top}px)`, pointerEvents: "none", position: "absolute", zIndex: 30000, overflow: "visible" }}>
-                    {InteractionUtils.CreatePolyline(l, b.left, b.top, ActiveInkColor(), ActiveInkWidth(), ActiveInkBezierApprox(), 1, 1, this.InkShape)}
+                    {InteractionUtils.CreatePolyline(l, b.left, b.top, ActiveInkColor(), ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), 1, 1, this.InkShape, "none", false)}
                 </svg>;
             }),
             this._points.length <= 1 ? (null) : <svg width={B.width} height={B.height} style={{ transform: `translate(${B.left}px, ${B.top}px)`, pointerEvents: "none", position: "absolute", zIndex: 30000, overflow: "visible" }}>
-                {InteractionUtils.CreatePolyline(this._points, B.left, B.top, ActiveInkColor(), ActiveInkWidth(), ActiveInkBezierApprox(), 1, 1, this.InkShape)}
+                {InteractionUtils.CreatePolyline(this._points, B.left, B.top, ActiveInkColor(), ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), 1, 1, this.InkShape, "none", false)}
             </svg>]
         ];
     }
@@ -901,12 +906,20 @@ Scripting.addGlobal("GestureOverlay", GestureOverlay);
 Scripting.addGlobal(function setToolglass(tool: any) {
     runInAction(() => GestureOverlay.Instance.Tool = tool);
 });
-Scripting.addGlobal(function setPen(width: any, color: any) {
+Scripting.addGlobal(function setPen(width: any, color: any, fill: any, arrowStart: any, arrowEnd: any, dash: any) {
     runInAction(() => {
         GestureOverlay.Instance.SavedColor = ActiveInkColor();
         SetActiveInkColor(color);
         GestureOverlay.Instance.SavedWidth = ActiveInkWidth();
         SetActiveInkWidth(width);
+        GestureOverlay.Instance.SavedFill = ActiveFillColor();
+        SetActiveFillColor(fill);
+        GestureOverlay.Instance.SavedArrowStart = ActiveArrowStart();
+        SetActiveArrowStart(arrowStart);
+        GestureOverlay.Instance.SavedArrowEnd = ActiveArrowEnd();
+        SetActiveArrowStart(arrowEnd);
+        GestureOverlay.Instance.SavedDash = ActiveDash();
+        SetActiveDash(dash);
     });
 });
 Scripting.addGlobal(function resetPen() {
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index a7650163f..324665aea 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -58,11 +58,13 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
         const points = InteractionUtils.CreatePolyline(data, left, top,
             strokeColor,
             strokeWidth.toString(),
-            StrCast(this.layoutDoc.strokeBezier, ActiveInkBezierApprox()), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5);
+            StrCast(this.layoutDoc.strokeBezier, ActiveInkBezierApprox()), StrCast(this.layoutDoc.fillColor, ActiveFillColor()), StrCast(this.layoutDoc.arrowStart, ActiveArrowStart()), StrCast(this.layoutDoc.arrowEnd, ActiveArrowEnd()), StrCast(this.layoutDoc.dash, ActiveDash()), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5);
         const hpoints = InteractionUtils.CreatePolyline(data, left, top,
             this.props.isSelected() && strokeWidth > 5 ? strokeColor : "transparent",
+            // strokeColor,
             (strokeWidth + 15).toString(),
-            StrCast(this.layoutDoc.strokeBezier, ActiveInkBezierApprox()), scaleX, scaleY, "", this.props.active() ? "visiblestroke" : "none", false);
+            StrCast(this.layoutDoc.strokeBezier, ActiveInkBezierApprox()), StrCast(this.layoutDoc.fillColor, ActiveFillColor()), StrCast(this.layoutDoc.arrowStart, ActiveArrowStart()), StrCast(this.layoutDoc.arrowEnd, ActiveArrowEnd()), StrCast(this.layoutDoc.dash, ActiveDash()), scaleX, scaleY, "", this.props.active() ? "visiblestroke" : "none", false);
+        console.log("#" + strokeColor);
         return (
             <svg className="inkingStroke"
                 width={width}
@@ -70,7 +72,8 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
                 style={{
                     pointerEvents: this.props.Document.isInkMask ? "all" : "none",
                     transform: this.props.Document.isInkMask ? "translate(2500px, 2500px)" : undefined,
-                    mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? "multiply" : "unset"
+                    mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? "multiply" : "unset",
+                    overflow: "visible",
                 }}
                 onContextMenu={() => {
                     ContextMenu.Instance.addItem({ description: "Analyze Stroke", event: this.analyzeStrokes, icon: "paint-brush" });
@@ -93,6 +96,18 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
                             <feMergeNode in="SourceGraphic"></feMergeNode>
                         </feMerge>
                     </filter>
+                    {/* <marker id="arrow" markerWidth="10" markerHeight="10" refX="0" refY="3" orient="auto" markerUnits="strokeWidth">
+                        <path d="M0,0 L0,6 L9,3 z" fill="black" />
+                    </marker> */}
+                    {/* <marker id="arrowHead" orient="auto" overflow="visible" refX="10" refY="3.5" markerWidth="10" markerHeight="7">
+                        <polygon points="10 0, 10 7, 0 3.5" fill="dodgerblue" />
+                    </marker>
+                    <marker id="arrowEnd" orient="auto" overflow="visible" refX="0" refY="3.5" markerWidth="10" markerHeight="7">
+                        <polygon points="0 0, 10 3.5, 0 7" fill="dodgerblue" />
+                    </marker> */}
+                    {/* <marker id="dot" orient="auto" overflow="visible">
+                        <circle r={strokeWidth} fill={"#" + strokeColor} />
+                    </marker> */}
                 </defs>
                 {hpoints}
                 {points}
@@ -105,17 +120,33 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
 export function SetActiveInkWidth(width: string): void { !isNaN(parseInt(width)) && ActiveInkPen() && (ActiveInkPen().activeInkWidth = width); }
 export function SetActiveBezierApprox(bezier: string): void { ActiveInkPen() && (ActiveInkPen().activeInkBezier = isNaN(parseInt(bezier)) ? "" : bezier); }
 export function SetActiveInkColor(value: string) { ActiveInkPen() && (ActiveInkPen().activeInkColor = value); }
+export function SetActiveFillColor(value: string) { ActiveInkPen() && (ActiveInkPen().activeFillColor = value); }
+export function SetActiveArrowStart(value: string) { ActiveInkPen() && (ActiveInkPen().activeArrowStart = value); }
+export function SetActiveArrowEnd(value: string) { ActiveInkPen() && (ActiveInkPen().activeArrowEnd = value); }
+export function SetActiveDash(dash: string): void { !isNaN(parseInt(dash)) && ActiveInkPen() && (ActiveInkPen().activeDash = dash); }
 export function ActiveInkPen(): Doc { return Cast(Doc.UserDoc().activeInkPen, Doc, null); }
 export function ActiveInkColor(): string { return StrCast(ActiveInkPen()?.activeInkColor, "black"); }
+export function ActiveFillColor(): string { return StrCast(ActiveInkPen()?.activeFillColor, "none"); }
+export function ActiveArrowStart(): string { return StrCast(ActiveInkPen()?.activeArrowStart, "none"); }
+export function ActiveArrowEnd(): string { return StrCast(ActiveInkPen()?.activeArrowEnd, "none"); }
+export function ActiveDash(): string { return StrCast(ActiveInkPen()?.activeDash, "0"); }
 export function ActiveInkWidth(): string { return StrCast(ActiveInkPen()?.activeInkWidth, "1"); }
 export function ActiveInkBezierApprox(): string { return StrCast(ActiveInkPen()?.activeInkBezier); }
-Scripting.addGlobal(function activateBrush(pen: any, width: any, color: any) {
+Scripting.addGlobal(function activateBrush(pen: any, width: any, color: any, fill: any, arrowStart: any, arrowEnd: any, dash: any) {
     Doc.SetSelectedTool(pen ? InkTool.Highlighter : InkTool.None);
     SetActiveInkWidth(width);
     SetActiveInkColor(color);
+    SetActiveFillColor(fill);
+    SetActiveArrowStart(arrowStart);
+    SetActiveArrowEnd(arrowEnd);
+    SetActiveDash(dash);
 });
 Scripting.addGlobal(function activateEraser(pen: any) { return Doc.SetSelectedTool(pen ? InkTool.Eraser : InkTool.None); });
 Scripting.addGlobal(function activateStamp(pen: any) { return Doc.SetSelectedTool(pen ? InkTool.Stamp : InkTool.None); });
 Scripting.addGlobal(function deactivateInk() { return Doc.SetSelectedTool(InkTool.None); });
 Scripting.addGlobal(function setInkWidth(width: any) { return SetActiveInkWidth(width); });
-Scripting.addGlobal(function setInkColor(color: any) { return SetActiveInkColor(color); });
\ No newline at end of file
+Scripting.addGlobal(function setInkColor(color: any) { return SetActiveInkColor(color); });
+Scripting.addGlobal(function setFillColor(fill: any) { return SetActiveFillColor(fill); });
+Scripting.addGlobal(function setActiveArrowStart(arrowStart: any) { return SetActiveArrowStart(arrowStart); });
+Scripting.addGlobal(function setActiveArrowEnd(arrowEnd: any) { return SetActiveArrowStart(arrowEnd); });
+Scripting.addGlobal(function setActiveDash(dash: any) { return SetActiveDash(dash); });
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 678ad2a53..b97ac286c 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -45,7 +45,7 @@ import React = require("react");
 import { CollectionViewType } from "../CollectionView";
 import { Timeline } from "../../animationtimeline/Timeline";
 import { SnappingManager } from "../../../util/SnappingManager";
-import { InkingStroke, ActiveInkColor, ActiveInkWidth, ActiveInkBezierApprox } from "../../InkingStroke";
+import { InkingStroke, ActiveArrowStart, ActiveArrowEnd, ActiveInkColor, ActiveFillColor, ActiveInkWidth, ActiveInkBezierApprox, ActiveDash } from "../../InkingStroke";
 
 library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload);
 
@@ -456,7 +456,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             case GestureUtils.Gestures.Stroke:
                 const points = ge.points;
                 const B = this.getTransform().transformBounds(ge.bounds.left, ge.bounds.top, ge.bounds.width, ge.bounds.height);
-                const inkDoc = Docs.Create.InkDocument(ActiveInkColor(), Doc.GetSelectedTool(), ActiveInkWidth(), ActiveInkBezierApprox(), points, { title: "ink stroke", x: B.x, y: B.y, _width: B.width, _height: B.height });
+                const inkDoc = Docs.Create.InkDocument(ActiveInkColor(), Doc.GetSelectedTool(), ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), points, { title: "ink stroke", x: B.x, y: B.y, _width: B.width, _height: B.height });
                 this.addDocument(inkDoc);
                 e.stopPropagation();
                 break;
diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
index 5a27f74e5..96a9cbbdb 100644
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
@@ -3,25 +3,39 @@ import AntimodeMenu from "../../AntimodeMenu";
 import { observer } from "mobx-react";
 import { observable, action, computed } from "mobx";
 import "./InkOptionsMenu.scss";
-import { ActiveInkColor, ActiveInkBezierApprox, SetActiveInkWidth, SetActiveInkColor, SetActiveBezierApprox } from "../../InkingStroke";
+import { ActiveInkColor, ActiveInkBezierApprox, ActiveFillColor, ActiveArrowStart, ActiveArrowEnd, SetActiveInkWidth, SetActiveInkColor, SetActiveBezierApprox, SetActiveFillColor, SetActiveArrowStart, SetActiveArrowEnd, ActiveDash, SetActiveDash } from "../../InkingStroke";
 import { Scripting } from "../../../util/Scripting";
 import { InkTool } from "../../../../fields/InkField";
 import { ColorState } from "react-color";
 import { Utils } from "../../../../Utils";
 import GestureOverlay from "../../GestureOverlay";
 import { Doc } from "../../../../fields/Doc";
+import { SelectionManager } from "../../../util/SelectionManager";
+import { DocumentView } from "../../../views/nodes/DocumentView";
+import { Document } from "../../../../fields/documentSchemas";
+import { DocumentType } from "../../../documents/DocumentTypes";
 
 @observer
 export default class InkOptionsMenu extends AntimodeMenu {
     static Instance: InkOptionsMenu;
 
-    private _palette = ["D0021B", "F5A623", "F8E71C", "8B572A", "7ED321", "417505", "9013FE", "4A90E2", "50E3C2", "B8E986", "000000", "4A4A4A", "9B9B9B", "FFFFFF"];
+    private _palette = ["D0021B", "F5A623", "F8E71C", "8B572A", "7ED321", "417505", "9013FE", "4A90E2", "50E3C2", "B8E986", "000000", "4A4A4A", "9B9B9B", "FFFFFF", "none"];
     private _width = ["1", "5", "10", "100", "200", "300"];
-    private _buttons = ["circle", "triangle", "rectangle", "arrow", "line"];
-    private _icons = ["O", "∆", "ロ", "➜", "-"];
+    // private _buttons = ["circle", "triangle", "rectangle", "arrow", "line"];
+    // private _icons = ["O", "∆", "ロ", "➜", "-"];
+    private _buttons = ["circle", "triangle", "rectangle", "line", ""];
+    private _icons = ["O", "∆", "ロ", "-", " "];
+    //arrowStart and arrowEnd must match and defs must exist in Inking Stroke
+    private _arrowStart = ["url(#arrowHead)", "url(#arrowHead)", "url(#dot)", "url(#dot)", "none"];
+    private _arrowEnd = ["none", "url(#arrowEnd)", "none", "url(#dot)", "none"];
+    private _arrowIcons = ["➡︎", "↔︎", "o-", "o-o", " "];
 
     @observable _colorBtn = false;
     @observable _widthBtn = false;
+    @observable _fillBtn = false;
+    @observable _arrowBtn = false;
+    @observable _dashBtn = false;
+    @observable _shapeBtn = false;
 
     constructor(props: Readonly<{}>) {
         super(props);
@@ -29,18 +43,103 @@ export default class InkOptionsMenu extends AntimodeMenu {
         this._canFade = false; // don't let the inking menu fade away
     }
 
+    getColors = () => {
+        return this._palette;
+    }
+
+    @action
+    changeArrow = (arrowStart: string, arrowEnd: string) => {
+        SetActiveArrowStart(arrowStart);
+        SetActiveArrowEnd(arrowEnd);
+    }
+
     @action
-    changeColor = (color: string) => {
+    changeColor = (color: string, type: string) => {
         const col: ColorState = {
             hex: color, hsl: { a: 0, h: 0, s: 0, l: 0, source: "" }, hsv: { a: 0, h: 0, s: 0, v: 0, source: "" },
             rgb: { a: 0, r: 0, b: 0, g: 0, source: "" }, oldHue: 0, source: "",
         };
-        SetActiveInkColor(Utils.colorString(col));
+        if (type === "color") {
+            SetActiveInkColor(Utils.colorString(col));
+        } else if (type === "fill") {
+            SetActiveFillColor(Utils.colorString(col));
+        }
     }
 
+    @action
+    editProperties = (value: any, field: string) => {
+        SelectionManager.SelectedDocuments().forEach(action((element: DocumentView) => {
+            const doc = Document(element.rootDoc);
+            if (doc.type === DocumentType.INK) {
+                switch (field) {
+                    case "width":
+                        doc.strokeWidth = Number(value);
+                        break;
+                    case "color":
+                        doc.color = String(value);
+                        break;
+                    case "fill":
+                        doc.fillColor = String(value);
+                        break;
+                    case "bezier":
+                        // doc.strokeBezier === 300 ? doc.strokeBezier = 0 : doc.strokeBezier = 300;
+                        break;
+                    case "arrowStart":
+                        doc.arrowStart = String(value);
+                        break;
+                    case "arrowEnd":
+                        doc.arrowEnd = String(value);
+                        break;
+                    case "dash":
+                        doc.dash = Number(value);
+                    default:
+                        break;
+                }
+            }
+        }));
+    }
+
+
     @action
     changeBezier = (e: React.PointerEvent): void => {
         SetActiveBezierApprox(!ActiveInkBezierApprox() ? "300" : "");
+        this.editProperties(0, "bezier");
+    }
+    @action
+    changeDash = (e: React.PointerEvent): void => {
+        SetActiveDash(ActiveDash() === "0" ? "2" : "0");
+        this.editProperties(ActiveDash(), "dash");
+    }
+
+    @computed get arrowPicker() {
+        var currIcon;
+        for (var i = 0; i < this._arrowStart.length; i++) {
+            if (this._arrowStart[i] === ActiveArrowStart() && this._arrowEnd[i] === ActiveArrowEnd()) {
+                currIcon = this._arrowIcons[i];
+            }
+        }
+        var arrowPicker = <button
+            className="antimodeMenu-button"
+            key="arrow"
+            onPointerDown={action(e => this._arrowBtn = !this._arrowBtn)}
+            style={{ backgroundColor: this._arrowBtn ? "121212" : "" }}>
+            {currIcon}
+        </button>;
+        if (this._arrowBtn) {
+            arrowPicker = <div className="btn2-group" key="arrows">
+                {arrowPicker}
+                {this._arrowStart.map((arrowStart, i) => {
+                    return <button
+                        className="antimodeMenu-button"
+                        key={arrowStart}
+                        onPointerDown={action(() => { SetActiveArrowStart(arrowStart); SetActiveArrowEnd(this._arrowEnd[i]); this.editProperties(arrowStart, "arrowStart"), this.editProperties(this._arrowEnd[i], "arrowEnd"); this._arrowBtn = false; })}
+                        style={{ backgroundColor: this._arrowBtn ? "121212" : "" }}>
+                        {this._arrowIcons[i]}
+                    </button>;
+                })}
+            </div>;
+        }
+        return arrowPicker;
     }
 
     @computed get widthPicker() {
@@ -58,7 +157,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
                     return <button
                         className="antimodeMenu-button"
                         key={wid}
-                        onPointerDown={action(() => { SetActiveInkWidth(wid); this._widthBtn = false; })}
+                        onPointerDown={action(() => { SetActiveInkWidth(wid); this._widthBtn = false; this.editProperties(wid, "width"); })}
                         style={{ backgroundColor: this._widthBtn ? "121212" : "" }}>
                         {wid}
                     </button>;
@@ -68,6 +167,8 @@ export default class InkOptionsMenu extends AntimodeMenu {
         return widthPicker;
     }
 
+
+
     @computed get colorPicker() {
         var colorPicker = <button
             className="antimodeMenu-button"
@@ -84,7 +185,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
                     return <button
                         className="antimodeMenu-button"
                         key={color}
-                        onPointerDown={action(() => { this.changeColor(color); this._colorBtn = false; })}
+                        onPointerDown={action(() => { this.changeColor(color, "color"); this._colorBtn = false; this.editProperties(color, "color"); })}
                         style={{ backgroundColor: this._colorBtn ? "121212" : "" }}>
                         <div className="color-preview" style={{ backgroundColor: color }}></div>
                     </button>;
@@ -94,6 +195,35 @@ export default class InkOptionsMenu extends AntimodeMenu {
         return colorPicker;
     }
 
+    @computed get fillPicker() {
+        var fillPicker = <button
+            className="antimodeMenu-button"
+            key="fill"
+            title="fillChanger"
+            onPointerDown={action(e => this._fillBtn = !this._fillBtn)}
+            style={{ backgroundColor: this._fillBtn ? "121212" : "" }}>
+            <div className="color-preview" style={{ backgroundColor: ActiveFillColor() ?? "121212" }}></div>
+        </button>;
+        if (this._fillBtn) {
+            fillPicker = <div className="btn-group" key="fill">
+                {fillPicker}
+                {this._palette.map(color => {
+                    return <button
+                        className="antimodeMenu-button"
+                        key={color}
+                        onPointerDown={action(() => { this.changeColor(color, "fill"); this._fillBtn = false; this.editProperties(color, "fill"); })}
+                        style={{ backgroundColor: this._fillBtn ? "121212" : "" }}>
+                        <div className="color-preview" style={{ backgroundColor: color }}></div>
+                    </button>;
+                })}
+
+            </div>;
+        }
+        return fillPicker;
+    }
+
+
+
     @computed get shapeButtons() {
         return <>
             {this._buttons.map((btn, i) => <button
@@ -103,28 +233,79 @@ export default class InkOptionsMenu extends AntimodeMenu {
                 onPointerDown={action(e => GestureOverlay.Instance.InkShape = btn)}
                 style={{ backgroundColor: btn === GestureOverlay.Instance.InkShape ? "121212" : "" }}>
                 {this._icons[i]}
-            </button>)},
+            </button>)}
         </>;
     }
 
+    @computed get shapePicker() {
+        var currIcon;
+        if (GestureOverlay.Instance.InkShape === "") {
+            currIcon = "S";
+        } else {
+            for (var i = 0; i < this._icons.length; i++) {
+                if (GestureOverlay.Instance.InkShape === this._buttons[i]) {
+                    currIcon = this._icons[i];
+                }
+            }
+        }
+        var shapePicker = <button
+            className="antimodeMenu-button"
+            key="shape"
+            onPointerDown={action(e => this._shapeBtn = !this._shapeBtn)}
+            style={{ backgroundColor: this._widthBtn ? "121212" : "" }}>
+            {currIcon}
+        </button>;
+        if (this._shapeBtn) {
+            shapePicker = <div className="btn2-group" key="shape">
+                {shapePicker}
+                {this._buttons.map((btn, i) => {
+                    return <button
+                        className="antimodeMenu-button"
+                        title={`Draw ${btn}`}
+                        key={btn}
+                        onPointerDown={action((e) => { GestureOverlay.Instance.InkShape = btn; this._shapeBtn = false; })}
+                        style={{ backgroundColor: this._shapeBtn ? "121212" : "" }}>
+                        {this._icons[i]}
+                    </button>;
+                })}
+            </div>;
+        }
+        return shapePicker;
+    }
+
     @computed get bezierButton() {
         return <button
             className="antimodeMenu-button"
             title="Bezier changer"
             key="bezier"
             onPointerDown={e => this.changeBezier(e)}
-            style={ { backgroundColor:ActiveInkBezierApprox() ? "121212":"" } }>
+            style={{ backgroundColor: ActiveInkBezierApprox() ? "121212" : "" }}>
             B
         </button>;
     }
 
+    @computed get dashButton() {
+        return <button
+            className="antimodeMenu-button"
+            title="dash changer"
+            key="dash"
+            onPointerDown={e => this.changeDash(e)}
+            style={{ backgroundColor: ActiveDash() !== "0" ? "121212" : "" }}>
+            ...
+        </button>;
+    }
+
     render() {
         const buttons = [
             <button className="antimodeMenu-button" title="Drag" key="drag" onPointerDown={e => this.dragStart(e)}>  ✜  </button>,
-            this.shapeButtons,
+            this.shapePicker,
+            // this.shapeButtons,
             this.bezierButton,
             this.widthPicker,
             this.colorPicker,
+            this.fillPicker,
+            this.arrowPicker,
+            this.dashButton
         ];
         return this.getElement(buttons);
     }
diff --git a/src/fields/InkField.ts b/src/fields/InkField.ts
index 51a5768bf..7cfd74cc4 100644
--- a/src/fields/InkField.ts
+++ b/src/fields/InkField.ts
@@ -1,7 +1,7 @@
 import { Deserializable } from "../client/util/SerializationHelper";
 import { serializable, custom, createSimpleSchema, list, object, map } from "serializr";
 import { ObjectField } from "./ObjectField";
-import { Copy, ToScriptString, ToString } from "./FieldSymbols";
+import { Copy, ToScriptString, ToString, Update } from "./FieldSymbols";
 
 export enum InkTool {
     None = "none",
@@ -31,6 +31,8 @@ const strokeDataSchema = createSimpleSchema({
 export class InkField extends ObjectField {
     @serializable(list(object(strokeDataSchema)))
     readonly inkData: InkData;
+    // inkData: InkData;
+
 
     constructor(data: InkData) {
         super();
-- 
cgit v1.2.3-70-g09d2


From 26d3d6c18d27a4ebb8f00e754bf3ea2cb5b08e00 Mon Sep 17 00:00:00 2001
From: yunahi <60233430+yunahi@users.noreply.github.com>
Date: Sat, 20 Jun 2020 02:39:20 +0900
Subject: updated menu/fixed icon

---
 src/client/util/CurrentUserUtils.ts                |  2 +-
 src/client/util/InteractionUtils.scss              |  4 ++
 src/client/util/InteractionUtils.tsx               | 65 +++++++++++++---------
 src/client/views/GestureOverlay.tsx                | 12 +++-
 src/client/views/InkingStroke.scss                 |  4 ++
 src/client/views/MainView.tsx                      |  4 +-
 .../collectionFreeForm/InkOptionsMenu.scss         |  7 ++-
 .../collectionFreeForm/InkOptionsMenu.tsx          | 42 +++++++++-----
 8 files changed, 94 insertions(+), 46 deletions(-)
 create mode 100644 src/client/util/InteractionUtils.scss

(limited to 'src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx')

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 3d0c0ef4a..324b08603 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -690,7 +690,7 @@ export class CurrentUserUtils {
         doc.activeInkPen = doc;
         doc.activeInkColor = StrCast(doc.activeInkColor, "rgb(0, 0, 0)");
         doc.activeInkWidth = StrCast(doc.activeInkWidth, "1");
-        doc.activeInkBezier = StrCast(doc.activeInkBezier, "");
+        doc.activeInkBezier = StrCast(doc.activeInkBezier, "0");
         doc.activeFillColor = StrCast(doc.activeFillColor, "none");
         doc.activeArrowStart = StrCast(doc.activeArrowStart, "none");
         doc.activeArrowEnd = StrCast(doc.activeArrowEnd, "none");
diff --git a/src/client/util/InteractionUtils.scss b/src/client/util/InteractionUtils.scss
new file mode 100644
index 000000000..6707157d4
--- /dev/null
+++ b/src/client/util/InteractionUtils.scss
@@ -0,0 +1,4 @@
+.halo {
+    opacity: 0.2;
+    stroke: black;
+}
\ No newline at end of file
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index c6b96df45..68dcbebe3 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -2,6 +2,7 @@ import React = require("react");
 import * as beziercurve from 'bezier-curve';
 import * as fitCurve from 'fit-curve';
 import InkOptionsMenu from "../views/collections/collectionFreeForm/InkOptionsMenu";
+import "./InteractionUtils.scss";
 
 export namespace InteractionUtils {
     export const MOUSETYPE = "mouse";
@@ -103,7 +104,7 @@ export namespace InteractionUtils {
             const newPoints: number[][] = [];
             const newPts: { X: number; Y: number; }[] = [];
             //convert to [][] for fitcurve module
-            for (var i = 0; i < points.length - 1; i++) {
+            for (var i = 0; i < points.length - 2; i++) {
                 newPoints.push([points[i].X, points[i].Y]);
             }
             const bezierCurves = fitCurve(newPoints, parseInt(bezier));
@@ -123,25 +124,38 @@ export namespace InteractionUtils {
         return (
             <svg>
                 <defs>
-
-                    {/* {makeArrow()} */}
                     <marker id="dot" orient="auto" overflow="visible">
-                        <circle r={1} fill="red" />
+                        <circle r={0.5} fill="context-stroke" />
                     </marker>
                     <marker id="arrowHead" orient="auto" overflow="visible" refX="3" refY="1" markerWidth="10" markerHeight="7">
                         {/* <rect width={strokeWidth} height={strokeWidth} transform='rotate(45)' fill="dodgerblue" /> */}
-                        <polygon points="3 0, 3 2, 0 1" fill="dodgerblue" />
+                        <polygon points="3 0, 3 2, 0 1" fill="black" />
                     </marker>
                     <marker id="arrowEnd" orient="auto" overflow="visible" refX="0" refY="1" markerWidth="10" markerHeight="7">
                         {/* <rect width={strokeWidth} height={strokeWidth} transform='rotate(45)' fill="dodgerblue" /> */}
-                        <polygon points="0 0, 3 1, 0 2" fill={"#" + color} />
+                        <polygon points="0 0, 3 1, 0 2" fill="black" />
                     </marker>
+
                 </defs>
+                {/* <polyline
+                    points={pts}
+                    style={{
+                        fill: fill,
+                        pointerEvents: pevents as any,
+                        stroke: drawHalo ? "grey" : "transparent",
+                        strokeWidth: parseInt(width) * 4,
+                        strokeLinejoin: "round",
+                        strokeLinecap: "round",
+                        strokeDasharray: dashArray
+                    }}
+                    markerStart={arrowStart}
+                    markerEnd={arrowEnd}
+                /> */}
 
                 <polyline
                     points={pts}
                     style={{
-                        filter: drawHalo ? "url(#dangerShine)" : undefined,
+                        // filter: drawHalo ? "url(#dangerShine)" : undefined,
                         fill: fill,
                         pointerEvents: pevents as any,
                         stroke: color ?? "rgb(0, 0, 0)",
@@ -153,6 +167,7 @@ export namespace InteractionUtils {
                     markerStart={arrowStart}
                     markerEnd={arrowEnd}
                 />
+
             </svg>
 
         );
@@ -239,24 +254,24 @@ export namespace InteractionUtils {
                 }
                 points.push({ X: Math.sqrt(Math.pow(radius, 2) - (Math.pow((top - centerY), 2))) + centerX, Y: top });
                 return points;
-            case "arrow":
-                const x1 = left;
-                const y1 = top;
-                const x2 = right;
-                const y2 = bottom;
-                const L1 = Math.sqrt(Math.pow(Math.abs(x1 - x2), 2) + (Math.pow(Math.abs(y1 - y2), 2)));
-                const L2 = L1 / 5;
-                const angle = 0.785398;
-                const x3 = x2 + (L2 / L1) * ((x1 - x2) * Math.cos(angle) + (y1 - y2) * Math.sin(angle));
-                const y3 = y2 + (L2 / L1) * ((y1 - y2) * Math.cos(angle) - (x1 - x2) * Math.sin(angle));
-                const x4 = x2 + (L2 / L1) * ((x1 - x2) * Math.cos(angle) - (y1 - y2) * Math.sin(angle));
-                const y4 = y2 + (L2 / L1) * ((y1 - y2) * Math.cos(angle) + (x1 - x2) * Math.sin(angle));
-                points.push({ X: x1, Y: y1 });
-                points.push({ X: x2, Y: y2 });
-                points.push({ X: x3, Y: y3 });
-                points.push({ X: x4, Y: y4 });
-                points.push({ X: x2, Y: y2 });
-                return points;
+            // case "arrow":
+            //     const x1 = left;
+            //     const y1 = top;
+            //     const x2 = right;
+            //     const y2 = bottom;
+            //     const L1 = Math.sqrt(Math.pow(Math.abs(x1 - x2), 2) + (Math.pow(Math.abs(y1 - y2), 2)));
+            //     const L2 = L1 / 5;
+            //     const angle = 0.785398;
+            //     const x3 = x2 + (L2 / L1) * ((x1 - x2) * Math.cos(angle) + (y1 - y2) * Math.sin(angle));
+            //     const y3 = y2 + (L2 / L1) * ((y1 - y2) * Math.cos(angle) - (x1 - x2) * Math.sin(angle));
+            //     const x4 = x2 + (L2 / L1) * ((x1 - x2) * Math.cos(angle) - (y1 - y2) * Math.sin(angle));
+            //     const y4 = y2 + (L2 / L1) * ((y1 - y2) * Math.cos(angle) + (x1 - x2) * Math.sin(angle));
+            //     points.push({ X: x1, Y: y1 });
+            //     points.push({ X: x2, Y: y2 });
+            //     points.push({ X: x3, Y: y3 });
+            //     points.push({ X: x4, Y: y4 });
+            //     points.push({ X: x2, Y: y2 });
+            //     return points;
             case "line":
                 points.push({ X: left, Y: top });
                 points.push({ X: right, Y: bottom });
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 5b6cbc372..01ef0b664 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -681,6 +681,10 @@ export default class GestureOverlay extends Touchable {
         } else {
             this._points = [];
         }
+        SetActiveArrowStart("none");
+        GestureOverlay.Instance.SavedArrowStart = ActiveArrowStart();
+        SetActiveArrowEnd("none");
+        GestureOverlay.Instance.SavedArrowEnd = ActiveArrowEnd();
         document.removeEventListener("pointermove", this.onPointerMove);
         document.removeEventListener("pointerup", this.onPointerUp);
     }
@@ -692,7 +696,9 @@ export default class GestureOverlay extends Touchable {
         var left = Math.min(...xs);
         var bottom = Math.max(...ys);
         var top = Math.min(...ys);
-
+        if (shape === "noRec") {
+            return;
+        }
         if (!gesture) {
             //if shape options is activated in inkOptionMenu
             //take second to last point because _point[length-1] is _points[0]
@@ -751,7 +757,7 @@ export default class GestureOverlay extends Touchable {
             case "line":
                 this._points.push({ X: left, Y: top });
                 this._points.push({ X: right, Y: bottom });
-                this._points.push({ X: right, Y: bottom - 1 });
+                // this._points.push({ X: right, Y: bottom - 1 });
                 break;
             case "arrow":
                 const x1 = left;
@@ -770,7 +776,7 @@ export default class GestureOverlay extends Touchable {
                 this._points.push({ X: x3, Y: y3 });
                 this._points.push({ X: x4, Y: y4 });
                 this._points.push({ X: x2, Y: y2 });
-                this._points.push({ X: x1, Y: y1 - 1 });
+            // this._points.push({ X: x1, Y: y1 - 1 });
         }
     }
 
diff --git a/src/client/views/InkingStroke.scss b/src/client/views/InkingStroke.scss
index 433433a42..30ab1967e 100644
--- a/src/client/views/InkingStroke.scss
+++ b/src/client/views/InkingStroke.scss
@@ -4,4 +4,8 @@
     stroke-linecap: round;
     overflow: visible !important;
     transform-origin: top left;
+
+    svg:not(:root) {
+        overflow: visible !important;
+    }
 }
\ No newline at end of file
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 3677746cd..15a6239be 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -5,7 +5,7 @@ import {
     faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt,
     faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter,
     faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote,
-    faThumbtack, faTree, faTv, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye
+    faThumbtack, faTree, faTv, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faArrowsAlt
 } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { action, computed, configure, observable, reaction, runInAction } from 'mobx';
@@ -129,7 +129,7 @@ export class MainView extends React.Component {
             faQuestionCircle, faArrowLeft, faArrowRight, faArrowDown, faArrowUp, faBolt, faBullseye, faCaretUp, faCat, faCheck, faChevronRight, faClipboard, faClone, faCloudUploadAlt,
             faCommentAlt, faCompressArrowsAlt, faCut, faEllipsisV, faEraser, faExclamation, faFileAlt, faFileAudio, faFilePdf, faFilm, faFilter, faFont, faGlobeAsia, faHighlighter,
             faLongArrowAltRight, faMicrophone, faMousePointer, faMusic, faObjectGroup, faPause, faPen, faPenNib, faPhone, faPlay, faPortrait, faRedoAlt, faStamp, faStickyNote, faTrashAlt, faAngleRight, faBell,
-            faThumbtack, faTree, faTv, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye);
+            faThumbtack, faTree, faTv, faUndoAlt, faVideo, faAsterisk, faBrain, faImage, faPaintBrush, faTimes, faEye, faArrowsAlt);
         this.initEventListeners();
         this.initAuthenticationRouters();
     }
diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss
index a7f4d4e53..a9fab4c1e 100644
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss
+++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss
@@ -1,5 +1,10 @@
 .antimodeMenu-button {
-    .color-preview {
+    .color-previewI {
+        width: 100%;
+        height: 40%;
+    }
+
+    .color-previewII {
         width: 100%;
         height: 100%;
     }
diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
index 96a9cbbdb..894227d84 100644
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
@@ -14,21 +14,26 @@ import { SelectionManager } from "../../../util/SelectionManager";
 import { DocumentView } from "../../../views/nodes/DocumentView";
 import { Document } from "../../../../fields/documentSchemas";
 import { DocumentType } from "../../../documents/DocumentTypes";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
+import { faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSubscript, faSuperscript, faIndent, faEyeDropper, faCaretDown, faPalette, faArrowsAlt, faHighlighter, faLink, faPaintRoller, faSleigh, faBars, faFillDrip, faBrush, faPenNib, faShapes, faArrowLeft, faEllipsisH, faBezierCurve } from "@fortawesome/free-solid-svg-icons";
+
+library.add(faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSuperscript, faSubscript, faIndent, faEyeDropper, faCaretDown, faPalette, faArrowsAlt, faHighlighter, faLink, faPaintRoller, faBars, faFillDrip, faBrush, faPenNib, faShapes, faArrowLeft, faEllipsisH, faBezierCurve);
 
 @observer
 export default class InkOptionsMenu extends AntimodeMenu {
     static Instance: InkOptionsMenu;
 
     private _palette = ["D0021B", "F5A623", "F8E71C", "8B572A", "7ED321", "417505", "9013FE", "4A90E2", "50E3C2", "B8E986", "000000", "4A4A4A", "9B9B9B", "FFFFFF", "none"];
-    private _width = ["1", "5", "10", "100", "200", "300"];
+    private _width = ["1", "5", "10", "100"];
     // private _buttons = ["circle", "triangle", "rectangle", "arrow", "line"];
     // private _icons = ["O", "∆", "ロ", "➜", "-"];
-    private _buttons = ["circle", "triangle", "rectangle", "line", ""];
-    private _icons = ["O", "∆", "ロ", "-", " "];
+    private _buttons = ["circle", "triangle", "rectangle", "line", "", "noRec"];
+    private _icons = ["O", "∆", "ロ", "––", " ", "✖︎"];
     //arrowStart and arrowEnd must match and defs must exist in Inking Stroke
     private _arrowStart = ["url(#arrowHead)", "url(#arrowHead)", "url(#dot)", "url(#dot)", "none"];
     private _arrowEnd = ["none", "url(#arrowEnd)", "none", "url(#dot)", "none"];
-    private _arrowIcons = ["➡︎", "↔︎", "o-", "o-o", " "];
+    private _arrowIcons = ["→", "↔︎", "・", "・・", " "];
 
     @observable _colorBtn = false;
     @observable _widthBtn = false;
@@ -116,6 +121,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
         for (var i = 0; i < this._arrowStart.length; i++) {
             if (this._arrowStart[i] === ActiveArrowStart() && this._arrowEnd[i] === ActiveArrowEnd()) {
                 currIcon = this._arrowIcons[i];
+
             }
         }
         var arrowPicker = <button
@@ -148,7 +154,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
             key="width"
             onPointerDown={action(e => this._widthBtn = !this._widthBtn)}
             style={{ backgroundColor: this._widthBtn ? "121212" : "" }}>
-            W
+            <FontAwesomeIcon icon="bars" size="lg" />
         </button>;
         if (this._widthBtn) {
             widthPicker = <div className="btn2-group" key="width">
@@ -176,7 +182,9 @@ export default class InkOptionsMenu extends AntimodeMenu {
             title="colorChanger"
             onPointerDown={action(e => this._colorBtn = !this._colorBtn)}
             style={{ backgroundColor: this._colorBtn ? "121212" : "" }}>
-            <div className="color-preview" style={{ backgroundColor: ActiveInkColor() ?? "121212" }}></div>
+            <FontAwesomeIcon icon="pen-nib" size="lg" />
+            <div className="color-previewI" style={{ backgroundColor: ActiveInkColor() ?? "121212" }}></div>
+
         </button>;
         if (this._colorBtn) {
             colorPicker = <div className="btn-group" key="color">
@@ -187,7 +195,8 @@ export default class InkOptionsMenu extends AntimodeMenu {
                         key={color}
                         onPointerDown={action(() => { this.changeColor(color, "color"); this._colorBtn = false; this.editProperties(color, "color"); })}
                         style={{ backgroundColor: this._colorBtn ? "121212" : "" }}>
-                        <div className="color-preview" style={{ backgroundColor: color }}></div>
+                        {/* <FontAwesomeIcon icon="pen-nib" size="lg" /> */}
+                        <div className="color-previewII" style={{ backgroundColor: color }}></div>
                     </button>;
                 })}
             </div>;
@@ -202,7 +211,8 @@ export default class InkOptionsMenu extends AntimodeMenu {
             title="fillChanger"
             onPointerDown={action(e => this._fillBtn = !this._fillBtn)}
             style={{ backgroundColor: this._fillBtn ? "121212" : "" }}>
-            <div className="color-preview" style={{ backgroundColor: ActiveFillColor() ?? "121212" }}></div>
+            <FontAwesomeIcon icon="fill-drip" size="lg" />
+            <div className="color-previewI" style={{ backgroundColor: ActiveFillColor() ?? "121212" }}></div>
         </button>;
         if (this._fillBtn) {
             fillPicker = <div className="btn-group" key="fill">
@@ -213,7 +223,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
                         key={color}
                         onPointerDown={action(() => { this.changeColor(color, "fill"); this._fillBtn = false; this.editProperties(color, "fill"); })}
                         style={{ backgroundColor: this._fillBtn ? "121212" : "" }}>
-                        <div className="color-preview" style={{ backgroundColor: color }}></div>
+                        <div className="color-previewII" style={{ backgroundColor: color }}></div>
                     </button>;
                 })}
 
@@ -240,7 +250,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
     @computed get shapePicker() {
         var currIcon;
         if (GestureOverlay.Instance.InkShape === "") {
-            currIcon = "S";
+            currIcon = <FontAwesomeIcon icon="shapes" size="lg" />;
         } else {
             for (var i = 0; i < this._icons.length; i++) {
                 if (GestureOverlay.Instance.InkShape === this._buttons[i]) {
@@ -252,7 +262,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
             className="antimodeMenu-button"
             key="shape"
             onPointerDown={action(e => this._shapeBtn = !this._shapeBtn)}
-            style={{ backgroundColor: this._widthBtn ? "121212" : "" }}>
+            style={{ backgroundColor: this._shapeBtn ? "121212" : "" }}>
             {currIcon}
         </button>;
         if (this._shapeBtn) {
@@ -280,7 +290,8 @@ export default class InkOptionsMenu extends AntimodeMenu {
             key="bezier"
             onPointerDown={e => this.changeBezier(e)}
             style={{ backgroundColor: ActiveInkBezierApprox() ? "121212" : "" }}>
-            B
+            <FontAwesomeIcon icon="bezier-curve" size="lg" />
+
         </button>;
     }
 
@@ -291,13 +302,16 @@ export default class InkOptionsMenu extends AntimodeMenu {
             key="dash"
             onPointerDown={e => this.changeDash(e)}
             style={{ backgroundColor: ActiveDash() !== "0" ? "121212" : "" }}>
-            ...
+            <FontAwesomeIcon icon="ellipsis-h" size="lg" />
+
         </button>;
     }
 
     render() {
         const buttons = [
-            <button className="antimodeMenu-button" title="Drag" key="drag" onPointerDown={e => this.dragStart(e)}>  ✜  </button>,
+            <button className="antimodeMenu-button" title="Drag" key="drag" onPointerDown={e => this.dragStart(e)}>
+                <FontAwesomeIcon icon="arrows-alt" size="lg" />
+            </button>,
             this.shapePicker,
             // this.shapeButtons,
             this.bezierButton,
-- 
cgit v1.2.3-70-g09d2


From 73299e354af3df1a5df712e24b32e14b5b0ec994 Mon Sep 17 00:00:00 2001
From: Bob Zeleznik <zzzman@gmail.com>
Date: Fri, 19 Jun 2020 18:17:59 -0400
Subject: a bunch of ink fixes

---
 src/client/util/InteractionUtils.tsx               | 31 +++++++++++-----------
 src/client/views/GestureOverlay.tsx                | 19 +++++++++----
 src/client/views/InkingStroke.tsx                  |  5 ++--
 .../collectionFreeForm/InkOptionsMenu.tsx          |  6 ++---
 4 files changed, 35 insertions(+), 26 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx')

diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index 9a9bb3d42..64facaca4 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -3,6 +3,7 @@ import * as beziercurve from 'bezier-curve';
 import * as fitCurve from 'fit-curve';
 import InkOptionsMenu from "../views/collections/collectionFreeForm/InkOptionsMenu";
 import "./InteractionUtils.scss";
+import { Utils } from "../../Utils";
 
 export namespace InteractionUtils {
     export const MOUSETYPE = "mouse";
@@ -93,15 +94,15 @@ export namespace InteractionUtils {
 
     export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number,
         color: string, width: number, strokeWidth: number, bezier: string, fill: string, arrowStart: string, arrowEnd: string,
-        dash: string, scalex: number, scaley: number, shape: string, pevents: string, drawHalo: boolean) {
+        dash: string, scalex: number, scaley: number, shape: string, pevents: string, drawHalo: boolean, nodefs: boolean) {
         let pts: { X: number; Y: number; }[] = [];
         if (shape) { //if any of the shape are true
             pts = makePolygon(shape, points);
         }
         else if (points.length > 1 && points[points.length - 1].X === points[0].X && points[points.length - 1].Y === points[0].Y) {
             //pointer is up (first and last points are the same)
-            points.pop();
             const newPoints = points.reduce((p, pts) => { p.push([pts.X, pts.Y]); return p; }, [] as number[][]);
+            newPoints.pop();
 
             const bezierCurves = fitCurve(newPoints, parseInt(bezier));
             for (const curve of bezierCurves) {
@@ -117,28 +118,26 @@ export namespace InteractionUtils {
             `${(pt.X - left - width / 2) * scalex + width / 2},
          ${(pt.Y - top - width / 2) * scaley + width / 2} `, "");
         const dashArray = String(Number(width) * Number(dash));
-
-        return (<svg>
-            <defs>
-                <marker id="dot" orient="auto" overflow="visible">
+        const defGuid = Utils.GenerateGuid();
+        return (<svg fill={fill === "none" ? color : fill}> {/* setting the svg fill sets the arrowhead fill */}
+            {nodefs ? (null) : <defs>
+                <marker id={`dot${defGuid}`} orient="auto" overflow="visible">
                     <circle r={0.5} fill="context-stroke" />
                 </marker>
-                <marker id="arrowHead" orient="auto" overflow="visible" refX="3" refY="1" markerWidth="10" markerHeight="7">
-                    {/* <rect width={strokeWidth} height={strokeWidth} transform='rotate(45)' fill="dodgerblue" /> */}
-                    <polygon points="3 0, 3 2, 0 1" fill={fill} />
+                <marker id={`arrowHead${defGuid}`} orient="auto" overflow="visible" refX="3" refY="0" markerWidth="10" markerHeight="7">
+                    <polygon points="10 -5, 10 5, 0 0" />
                 </marker>
-                <marker id="arrowEnd" orient="auto" overflow="visible" refX="0" refY="1" markerWidth="10" markerHeight="7">
-                    {/* <rect width={strokeWidth} height={strokeWidth} transform='rotate(45)' fill="dodgerblue" /> */}
-                    <polygon points="0 0, 3 1, 0 2" fill={fill} />
+                <marker id={`arrowEnd${defGuid}`} orient="auto" overflow="visible" refX="3" refY="1" markerWidth="10" markerHeight="7">
+                    <polygon points="0 0, 3 1, 0 2" />
                 </marker>
 
-            </defs>
+            </defs>}
 
             <polyline
                 points={strpts}
                 style={{
                     filter: drawHalo ? "url(#dangerShine)" : undefined,
-                    fill: "none",
+                    fill,
                     opacity: strokeWidth !== width ? 0.5 : undefined,
                     pointerEvents: pevents as any,
                     stroke: color ?? "rgb(0, 0, 0)",
@@ -146,8 +145,8 @@ export namespace InteractionUtils {
                     strokeLinejoin: "round",
                     strokeLinecap: "round"
                 }}
-                markerStart={arrowStart}
-                markerEnd={arrowEnd}
+                markerStart={`url(#${arrowStart + defGuid})`}
+                markerEnd={`url(#${arrowEnd + defGuid})`}
             />
 
         </svg>);
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 95dc2c7d4..43aa63eb1 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -24,6 +24,7 @@ import { RadialMenu } from "./nodes/RadialMenu";
 import HorizontalPalette from "./Palette";
 import { Touchable } from "./Touchable";
 import TouchScrollableMenu, { TouchScrollableMenuItem } from "./TouchScrollableMenu";
+import HeightLabel from "./collections/collectionMulticolumn/MultirowHeightLabel";
 
 @observer
 export default class GestureOverlay extends Touchable {
@@ -812,20 +813,28 @@ export default class GestureOverlay extends Touchable {
     }
 
     @computed get elements() {
-
-        const B = this.svgBounds;
         const width = Number(ActiveInkWidth());
+        const B = this.svgBounds;
+        B.left = B.left - width / 2;
+        B.right = B.right + width / 2;
+        B.top = B.top - width / 2;
+        B.bottom = B.bottom + width / 2;
+        B.width += width;
+        B.height += width;
         return [
             this.props.children,
             this._palette,
             [this._strokes.map((l, i) => {
                 const b = this.getBounds(l);
                 return <svg key={i} width={b.width} height={b.height} style={{ transform: `translate(${b.left}px, ${b.top}px)`, pointerEvents: "none", position: "absolute", zIndex: 30000, overflow: "visible" }}>
-                    {InteractionUtils.CreatePolyline(l, b.left, b.top, ActiveInkColor(), width, width, ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), 1, 1, this.InkShape, "none", false)}
+                    {InteractionUtils.CreatePolyline(l, b.left, b.top, ActiveInkColor(), width, width,
+                        ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(),
+                        ActiveDash(), 1, 1, this.InkShape, "none", false, false)}
                 </svg>;
             }),
-            this._points.length <= 1 ? (null) : <svg key="svg" width={B.width} height={B.height} style={{ transform: `translate(${B.left}px, ${B.top}px)`, pointerEvents: "none", position: "absolute", zIndex: 30000, overflow: "visible" }}>
-                {InteractionUtils.CreatePolyline(this._points, B.left, B.top, ActiveInkColor(), width, width, ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), 1, 1, this.InkShape, "none", false)}
+            this._points.length <= 1 ? (null) : <svg key="svg" width={B.width} height={B.height}
+                style={{ transform: `translate(${B.left}px, ${B.top}px)`, pointerEvents: "none", position: "absolute", zIndex: 30000, overflow: "visible" }}>
+                {InteractionUtils.CreatePolyline(this._points, B.left, B.top, ActiveInkColor(), width, width, ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), 1, 1, this.InkShape, "none", false, false)}
             </svg>]
         ];
     }
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index dc5d387d0..627760c38 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -15,6 +15,7 @@ import { FieldView, FieldViewProps } from "./nodes/FieldView";
 import React = require("react");
 import { Scripting } from "../util/Scripting";
 import { Doc } from "../../fields/Doc";
+import { NodeFlags } from "typescript";
 
 library.add(faPaintBrush);
 
@@ -56,11 +57,11 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
         const points = InteractionUtils.CreatePolyline(data, left, top, strokeColor, strokeWidth, strokeWidth,
             StrCast(this.layoutDoc.strokeBezier, ActiveInkBezierApprox()), StrCast(this.layoutDoc.fillColor, ActiveFillColor()),
             StrCast(this.layoutDoc.arrowStart, ActiveArrowStart()), StrCast(this.layoutDoc.arrowEnd, ActiveArrowEnd()),
-            StrCast(this.layoutDoc.dash, ActiveDash()), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5);
+            StrCast(this.layoutDoc.dash, ActiveDash()), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5, false);
         const hpoints = InteractionUtils.CreatePolyline(data, left, top,
             this.props.isSelected() && strokeWidth > 5 ? strokeColor : "transparent", strokeWidth, (strokeWidth + 15),
             StrCast(this.layoutDoc.strokeBezier, ActiveInkBezierApprox()), StrCast(this.layoutDoc.fillColor, ActiveFillColor()),
-            "none", "none", "0", scaleX, scaleY, "", this.props.active() ? "visiblestroke" : "none", false);
+            "none", "none", "0", scaleX, scaleY, "", this.props.active() ? "visiblestroke" : "none", false, true);
         return (
             <svg className="inkingStroke"
                 width={width}
diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
index f39f8f784..fb2640249 100644
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
@@ -24,15 +24,15 @@ library.add(faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSup
 export default class InkOptionsMenu extends AntimodeMenu {
     static Instance: InkOptionsMenu;
 
-    private _palette = ["D0021B", "F5A623", "F8E71C", "8B572A", "7ED321", "417505", "9013FE", "4A90E2", "50E3C2", "B8E986", "000000", "4A4A4A", "9B9B9B", "FFFFFF", "none"];
+    private _palette = ["#D0021B", "#F5A623", "#F8E71C", "#8B572A", "#7ED321", "#417505", "#9013FE", "#4A90E2", "#50E3C2", "#B8E986", "#000000", "#4A4A4A", "#9B9B9B", "#FFFFFF", "none"];
     private _width = ["1", "5", "10", "100"];
     // private _buttons = ["circle", "triangle", "rectangle", "arrow", "line"];
     // private _icons = ["O", "∆", "ロ", "➜", "-"];
     private _buttons = ["circle", "triangle", "rectangle", "line", "", "noRec"];
     private _icons = ["O", "∆", "ロ", "––", " ", "✖︎"];
     //arrowStart and arrowEnd must match and defs must exist in Inking Stroke
-    private _arrowStart = ["url(#arrowHead)", "url(#arrowHead)", "url(#dot)", "url(#dot)", "none"];
-    private _arrowEnd = ["none", "url(#arrowEnd)", "none", "url(#dot)", "none"];
+    private _arrowStart = ["arrowHead", "arrowHead", "dot", "dot", "none"];
+    private _arrowEnd = ["none", "arrowEnd", "none", "dot", "none"];
     private _arrowIcons = ["→", "↔︎", "・", "・・", " "];
 
     @observable _colorBtn = false;
-- 
cgit v1.2.3-70-g09d2


From 810da165c898973a098f0bfdb76727ab228d057a Mon Sep 17 00:00:00 2001
From: yunahi <60233430+yunahi@users.noreply.github.com>
Date: Wed, 24 Jun 2020 00:39:56 +0900
Subject: fixed inkmenu

---
 src/client/views/GestureOverlay.tsx                |  4 +++-
 .../collectionFreeForm/InkOptionsMenu.tsx          | 23 +++++++++++++++-------
 2 files changed, 19 insertions(+), 8 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx')

diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index 43aa63eb1..85695bbac 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -632,7 +632,9 @@ export default class GestureOverlay extends Touchable {
                 this.makePolygon(this.InkShape, false);
                 this.dispatchGesture(GestureUtils.Gestures.Stroke);
                 this._points = [];
-                this.InkShape = "";
+                if (this.InkShape !== "noRec") {
+                    this.InkShape = "";
+                }
             }
             // if we're not drawing in a toolglass try to recognize as gesture
             else {
diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
index fb2640249..e43e6bbdd 100644
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
@@ -16,7 +16,7 @@ import { Document } from "../../../../fields/documentSchemas";
 import { DocumentType } from "../../../documents/DocumentTypes";
 import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
 import { IconProp, library } from '@fortawesome/fontawesome-svg-core';
-import { faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSubscript, faSuperscript, faIndent, faEyeDropper, faCaretDown, faPalette, faArrowsAlt, faHighlighter, faLink, faPaintRoller, faSleigh, faBars, faFillDrip, faBrush, faPenNib, faShapes, faArrowLeft, faEllipsisH, faBezierCurve } from "@fortawesome/free-solid-svg-icons";
+import { faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSubscript, faSuperscript, faIndent, faEyeDropper, faCaretDown, faPalette, faArrowsAlt, faHighlighter, faLink, faPaintRoller, faSleigh, faBars, faFillDrip, faBrush, faPenNib, faShapes, faArrowLeft, faEllipsisH, faBezierCurve, } from "@fortawesome/free-solid-svg-icons";
 
 library.add(faBold, faItalic, faChevronLeft, faUnderline, faStrikethrough, faSuperscript, faSubscript, faIndent, faEyeDropper, faCaretDown, faPalette, faArrowsAlt, faHighlighter, faLink, faPaintRoller, faBars, faFillDrip, faBrush, faPenNib, faShapes, faArrowLeft, faEllipsisH, faBezierCurve);
 
@@ -28,12 +28,12 @@ export default class InkOptionsMenu extends AntimodeMenu {
     private _width = ["1", "5", "10", "100"];
     // private _buttons = ["circle", "triangle", "rectangle", "arrow", "line"];
     // private _icons = ["O", "∆", "ロ", "➜", "-"];
-    private _buttons = ["circle", "triangle", "rectangle", "line", "", "noRec"];
-    private _icons = ["O", "∆", "ロ", "––", " ", "✖︎"];
+    private _buttons = ["circle", "triangle", "rectangle", "line", "noRec", "",];
+    private _icons = ["O", "∆", "ロ", "⎯", "✖︎", " "];
     //arrowStart and arrowEnd must match and defs must exist in Inking Stroke
     private _arrowStart = ["arrowHead", "arrowHead", "dot", "dot", "none"];
     private _arrowEnd = ["none", "arrowEnd", "none", "dot", "none"];
-    private _arrowIcons = ["→", "↔︎", "・", "・・", " "];
+    private _arrowIcons = ["→", "↔︎", "•", "••", " "];
 
     @observable _colorBtn = false;
     @observable _widthBtn = false;
@@ -121,7 +121,9 @@ export default class InkOptionsMenu extends AntimodeMenu {
         for (var i = 0; i < this._arrowStart.length; i++) {
             if (this._arrowStart[i] === ActiveArrowStart() && this._arrowEnd[i] === ActiveArrowEnd()) {
                 currIcon = this._arrowIcons[i];
-
+                if (this._arrowIcons[i] === " ") {
+                    currIcon = "➤";
+                }
             }
         }
         var arrowPicker = <button
@@ -254,10 +256,17 @@ export default class InkOptionsMenu extends AntimodeMenu {
             shapePicker = <div className="btn2-group" key="shape">
                 {shapePicker}
                 {this._buttons.map((btn, i) => {
+                    var ttl = btn;
+                    if (btn === "") {
+                        ttl = "no shape";
+                    }
+                    if (btn === "noRec") {
+                        ttl = "disable shape recognition";
+                    }
                     return <button
                         className="antimodeMenu-button"
                         title={`Draw ${btn}`}
-                        key={btn}
+                        key={ttl}
                         onPointerDown={action((e) => { GestureOverlay.Instance.InkShape = btn; this._shapeBtn = false; })}
                         style={{ backgroundColor: this._shapeBtn ? "121212" : "" }}>
                         {this._icons[i]}
@@ -303,7 +312,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
             this.colorPicker,
             this.fillPicker,
             this.arrowPicker,
-            this.dashButton
+            this.dashButton,
         ];
         return this.getElement(buttons);
     }
-- 
cgit v1.2.3-70-g09d2


From bda2ce11499dce2f4647f582c9e4930bf18770ce Mon Sep 17 00:00:00 2001
From: yunahi <60233430+yunahi@users.noreply.github.com>
Date: Sat, 27 Jun 2020 01:40:00 +0900
Subject: fixed arrow/dot?

---
 src/client/util/InteractionUtils.tsx                          | 11 ++++++-----
 .../views/collections/collectionFreeForm/InkOptionsMenu.tsx   |  6 +++---
 2 files changed, 9 insertions(+), 8 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx')

diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index c38c9b9c2..3634fb704 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -121,12 +121,12 @@ export namespace InteractionUtils {
         return (<svg fill={fill === "none" ? color : fill}> {/* setting the svg fill sets the arrowhead fill */}
             {nodefs ? (null) : <defs>
                 <marker id={`dot${defGuid}`} orient="auto" overflow="visible">
-                    <circle r={0.5} fill="context-stroke" />
+                    <circle r={1} fill="context-stroke" />
                 </marker>
-                <marker id={`arrowHead${defGuid}`} orient="auto" overflow="visible" refX="3" refY="0" markerWidth="10" markerHeight="7">
-                    <polygon points="10 -5, 10 5, 0 0" />
+                <marker id={`arrowHead${defGuid}`} orient="auto" overflow="visible" refX="3" refY="1" markerWidth="10" markerHeight="7">
+                    <polygon points="3 0, 3 2, 0 1" />
                 </marker>
-                <marker id={`arrowEnd${defGuid}`} orient="auto" overflow="visible" refX="3" refY="1" markerWidth="10" markerHeight="7">
+                <marker id={`arrowEnd${defGuid}`} orient="auto" overflow="visible" refX="0" refY="1" markerWidth="10" markerHeight="7">
                     <polygon points="0 0, 3 1, 0 2" />
                 </marker>
 
@@ -142,7 +142,8 @@ export namespace InteractionUtils {
                     stroke: color ?? "rgb(0, 0, 0)",
                     strokeWidth: strokeWidth,
                     strokeLinejoin: "round",
-                    strokeLinecap: "round"
+                    strokeLinecap: "round",
+                    strokeDasharray: dashArray
                 }}
                 markerStart={`url(#${arrowStart + defGuid})`}
                 markerEnd={`url(#${arrowEnd + defGuid})`}
diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
index e43e6bbdd..f1032adaa 100644
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
@@ -303,9 +303,9 @@ export default class InkOptionsMenu extends AntimodeMenu {
 
     render() {
         const buttons = [
-            <button className="antimodeMenu-button" title="Drag" key="drag" onPointerDown={e => this.dragStart(e)}>
-                <FontAwesomeIcon icon="arrows-alt" size="lg" />
-            </button>,
+            // <button className="antimodeMenu-button" title="Drag" key="drag" onPointerDown={e => this.dragStart(e)}>
+            //     <FontAwesomeIcon icon="arrows-alt" size="lg" />
+            // </button>,
             this.shapePicker,
             this.bezierButton,
             this.widthPicker,
-- 
cgit v1.2.3-70-g09d2


From 56da30314c4d434c4b7bb8be94f3bcb5923790d8 Mon Sep 17 00:00:00 2001
From: Lionel Han <47760119+IGoByJoe@users.noreply.github.com>
Date: Mon, 29 Jun 2020 18:05:46 -0700
Subject: minor changes

---
 .../collectionFreeForm/InkOptionsMenu.tsx          |  5 ++-
 src/mobile/MobileInterface.tsx                     | 37 +++++++++++++---------
 2 files changed, 26 insertions(+), 16 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
index e5b7023a1..218cef183 100644
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
@@ -320,10 +320,13 @@ export default class InkOptionsMenu extends AntimodeMenu {
         ];
 
         const mobileButtons = [
-            ...this.shapeButtons,
+            this.shapePicker,
             this.bezierButton,
             this.widthPicker,
             this.colorPicker,
+            this.fillPicker,
+            this.arrowPicker,
+            this.dashButton,
         ];
 
         return (window.screen.width < 600 ? this.getElement(mobileButtons) : this.getElement(buttons));
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index a49bfb9b1..cb7319e03 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -56,6 +56,8 @@ export class MobileInterface extends React.Component {
     @observable private audioUploadActive: boolean = false;
     @observable private menuListView: boolean = false; //to switch between menu view (list / icon)
     @observable private _ink: boolean = false; //toggle whether ink is being dispalyed
+    @observable private inkButton: boolean = false;
+    @observable private undoButton: boolean = false;
 
     public _activeDoc: Doc = this.mainDoc; // doc updated as the active mobile page is updated (initially home menu)
     public _homeDoc: Doc = this.mainDoc; // home menu as a document
@@ -107,6 +109,10 @@ export class MobileInterface extends React.Component {
         this.renderView = renderView;
         // Ensures that switching to home is not registed
         UndoManager.undoStack.length = 0;
+
+        if (this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc && this._activeDoc !== this.userDoc.rightSidebarCollection && this._activeDoc.title !== "WORKSPACES") {
+            this.undoButton = true;
+        }
     }
 
     // For toggling the hamburger menu
@@ -445,7 +451,7 @@ export class MobileInterface extends React.Component {
         const freeformOptions: DocumentOptions = {
             x: 0,
             y: 400,
-            title: "Collection " + workspaceCount
+            title: "Collection " + workspaceCount,
         };
         const freeformDoc = CurrentUserUtils.GuestTarget || Docs.Create.FreeformDocument([], freeformOptions);
         const workspaceDoc = Docs.Create.StandardCollectionDockingDocument([{ doc: freeformDoc, initialWidth: 600, path: [Doc.UserDoc().myCatalog as Doc] }], { title: `Workspace ${workspaceCount}` }, id, "row");
@@ -493,19 +499,21 @@ export class MobileInterface extends React.Component {
 
     // DocButton that uses UndoManager and handles the opacity change if CanUndo is true
     @computed get undo() {
-        if (this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc && this._activeDoc !== this.userDoc.rightSidebarCollection && this._activeDoc.title !== "WORKSPACES") {
-            return (<>
-                <div className="docButton"
-                    style={{ backgroundColor: "black", color: "white", fontSize: "60", opacity: UndoManager.CanUndo() ? "1" : "0.4", }}
-                    id="undoButton"
-                    title="undo"
-                    onClick={(e: React.MouseEvent) => {
-                        UndoManager.Undo();
-                        e.stopPropagation();
-                    }}>
-                    <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="undo-alt" />
-                </div>
-            </>);
+        if (this.mainContainer) {
+            if (this._activeDoc.type === "collection" && this._activeDoc !== this._homeDoc && this._activeDoc !== this.userDoc.rightSidebarCollection && this._activeDoc.title !== "WORKSPACES") {
+                return (<>
+                    <div className="docButton"
+                        style={{ backgroundColor: "black", color: "white", fontSize: "60", opacity: UndoManager.CanUndo() ? "1" : "0.4", }}
+                        id="undoButton"
+                        title="undo"
+                        onClick={(e: React.MouseEvent) => {
+                            UndoManager.Undo();
+                            e.stopPropagation();
+                        }}>
+                        <FontAwesomeIcon className="documentdecorations-icon" size="sm" icon="undo-alt" />
+                    </div>
+                </>);
+            }
         }
     }
 
@@ -704,7 +712,6 @@ export class MobileInterface extends React.Component {
     }
 
     onDragOver = (e: React.DragEvent) => {
-        console.log("drag!");
         e.preventDefault();
         e.stopPropagation();
     }
-- 
cgit v1.2.3-70-g09d2


From 917098c107052f825e0f9b96bdb0706371862b90 Mon Sep 17 00:00:00 2001
From: Lionel Han <47760119+IGoByJoe@users.noreply.github.com>
Date: Mon, 29 Jun 2020 23:14:41 -0700
Subject: ink fixes

---
 .../views/collections/collectionFreeForm/InkOptionsMenu.tsx | 13 +------------
 src/client/views/nodes/DocumentView.tsx                     |  1 +
 src/mobile/MobileInterface.scss                             |  5 +++--
 src/mobile/MobileInterface.tsx                              |  8 +++++++-
 4 files changed, 12 insertions(+), 15 deletions(-)

(limited to 'src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx')

diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
index 218cef183..f47fca6ac 100644
--- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
+++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx
@@ -318,18 +318,7 @@ export default class InkOptionsMenu extends AntimodeMenu {
             this.arrowPicker,
             this.dashButton,
         ];
-
-        const mobileButtons = [
-            this.shapePicker,
-            this.bezierButton,
-            this.widthPicker,
-            this.colorPicker,
-            this.fillPicker,
-            this.arrowPicker,
-            this.dashButton,
-        ];
-
-        return (window.screen.width < 600 ? this.getElement(mobileButtons) : this.getElement(buttons));
+        return this.getElement(buttons);
     }
 }
 Scripting.addGlobal(function activatePen(penBtn: any) {
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 3b785a200..0ec676379 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -42,6 +42,7 @@ import { LinkAnchorBox } from './LinkAnchorBox';
 import { RadialMenu } from './RadialMenu';
 import React = require("react");
 import { DocumentLinksButton } from './DocumentLinksButton';
+import { MobileInterface } from '../../../mobile/MobileInterface';
 
 library.add(fa.faEdit, fa.faTrash, fa.faShare, fa.faDownload, fa.faExpandArrowsAlt, fa.faCompressArrowsAlt, fa.faLayerGroup, fa.faExternalLinkAlt, fa.faAlignCenter, fa.faCaretSquareRight,
     fa.faSquare, fa.faConciergeBell, fa.faWindowRestore, fa.faFolder, fa.faMapPin, fa.faLink, fa.faFingerprint, fa.faCrosshairs, fa.faDesktop, fa.faUnlock, fa.faLock, fa.faLaptopCode, fa.faMale,
diff --git a/src/mobile/MobileInterface.scss b/src/mobile/MobileInterface.scss
index ee39d4f50..4b32c3da0 100644
--- a/src/mobile/MobileInterface.scss
+++ b/src/mobile/MobileInterface.scss
@@ -401,14 +401,15 @@ body {
 .colorSelector {
     position: absolute;
     top: 550px;
-    left: 300px;
+    left: 280px;
     transform: translate(-50%, 0);
     z-index: 100;
     display: inline-flex;
     width: max-content;
     height: max-content;
     pointer-events: all;
-    font-size: 90px;
+    font-size: 80px;
+    user-select: none;
 }
 
 // Menu buttons for toggling between list and icon view
diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx
index 7ff82ccc4..54461c4cc 100644
--- a/src/mobile/MobileInterface.tsx
+++ b/src/mobile/MobileInterface.tsx
@@ -107,12 +107,18 @@ export class MobileInterface extends React.Component {
         this.renderView = renderView;
         // Ensures that switching to home is not registed
         UndoManager.undoStack.length = 0;
+        UndoManager.redoStack.length = 0;
     }
 
     // For toggling the hamburger menu
     @action
-    toggleSidebar = () => this.sidebarActive = !this.sidebarActive
+    toggleSidebar = () => {
+        this.sidebarActive = !this.sidebarActive;
 
+        if (this._ink) {
+            this.onSwitchInking();
+        }
+    }
     /**
      * Method called when 'Library' button is pressed on the home screen
      */
-- 
cgit v1.2.3-70-g09d2

