From 8824730d44f52ad41c2687205109a271f8c63e80 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 19 Apr 2021 12:27:33 -0400
Subject: started to cleanup comic mode.

---
 .../views/nodes/CollectionFreeFormDocumentView.tsx | 33 +++++++++++++---------
 1 file changed, 20 insertions(+), 13 deletions(-)

(limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx')

diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 1fda4cc5e..807a61094 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -37,10 +37,14 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     public static animFields = ["_height", "_width", "x", "y", "_scrollTop", "opacity"];  // fields that are configured to be animatable using animation frames
     @observable _animPos: number[] | undefined = undefined;
     @observable _contentView: DocumentView | undefined | null;
+    @computed get jitterRotation() {
+        const rot = this.random(-1, 1) * this.props.jitterRotation * (this.props.PanelWidth() > this.props.PanelHeight() ? 0.5 : 1);
+        return rot;
+    }
     random(min: number, max: number) { /* min should not be equal to max */ return min + ((Math.abs(this.X * this.Y) * 9301 + 49297) % 233280 / 233280) * (max - min); }
     get displayName() { return "CollectionFreeFormDocumentView(" + this.rootDoc.title + ")"; } // this makes mobx trace() statements more descriptive
     get maskCentering() { return this.props.Document.isInkMask ? InkingStroke.MaskDim / 2 : 0; }
-    get transform() { return `translate(${this.X - this.maskCentering}px, ${this.Y - this.maskCentering}px) rotate(${this.random(-1, 1) * this.props.jitterRotation}deg)`; }
+    get transform() { return `translate(${this.X - this.maskCentering}px, ${this.Y - this.maskCentering}px) rotate(${this.jitterRotation}deg)`; }
     get X() { return this.dataProvider ? this.dataProvider.x : (this.Document.x || 0); }
     get Y() { return this.dataProvider ? this.dataProvider.y : (this.Document.y || 0); }
     get ZInd() { return this.dataProvider ? this.dataProvider.zIndex : (this.Document.zIndex || 0); }
@@ -156,7 +160,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     returnThis = () => this;
     render() {
         TraceMobx();
-        const backgroundColor = () => this.props.styleProvider?.(this.Document, this.props, StyleProp.BackgroundColor);
+        const pw = this.panelWidth();
+        const ph = this.panelHeight();
+        const path = `M ${pw * .5} ${ph * .05}   C ${pw * .6} ${ph * .05} ${pw * .9} 0 ${pw * .95} ${ph * .05}   C ${pw} ${ph * .1} ${pw * .95} ${ph * .2} ${pw * .95} ${ph * .25}   C ${pw * .95} ${ph * .35} ${pw} ${ph * .9} ${pw * .95} ${ph * .95}  C ${pw * .9} ${ph} ${pw * .6} ${ph * .95} ${pw * .5} ${ph * .95}   C ${pw * .3} ${ph * .95} ${pw * .1} ${ph} ${pw * .05} ${ph * .95}  C 0 ${ph * .9} ${pw * .05} ${ph * .85} ${pw * .05} ${ph * .8}   C ${pw * .05} ${ph * .75} 0 ${ph * .1} ${pw * .05} ${ph * .05}   C ${pw * .1} 0 ${pw * .25} ${ph * .05} ${pw * .5} ${ph * .05}`;
         const divProps: DocumentViewProps = {
             ...this.props,
             CollectionFreeFormDocumentView: this.returnThis,
@@ -175,18 +181,19 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 transition: this.props.dataTransition ? this.props.dataTransition : this.dataProvider ? this.dataProvider.transition : StrCast(this.layoutDoc.dataTransition),
                 zIndex: this.ZInd,
                 mixBlendMode: StrCast(this.layoutDoc.mixBlendMode) as any,
-                display: this.ZInd === -99 ? "none" : undefined,
+                display: this.ZInd === -99 ? "none" : undefined
             }} >
-
-            {Doc.UserDoc().renderStyle !== "comic" ? (null) :
-                <div style={{ width: "100%", height: "100%", position: "absolute" }}>
-                    <svg style={{ transform: `scale(1,${this.props.PanelHeight() / this.props.PanelWidth()})`, transformOrigin: "top left", overflow: "visible" }} viewBox="0 0 12 14">
-                        <path d="M 7 0 C 9 -1 13 1 12 4 C 11 10 13 12 10 12 C 6 12 7 13 2 12 Q -1 11 0 8 C 1 4 0 4 0 2 C 0 0 1 0 1 0 C 3 0 3 1 7 0"
-                            style={{ stroke: "black", fill: backgroundColor(), strokeWidth: 0.2 }} />
-                    </svg>
-                </div>}
-
-            <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} />
+            {Doc.UserDoc().renderStyle !== "comic" ? <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} /> :
+                <>
+                    <div key="doc" style={{ clipPath: `path('${path}')` }}>
+                        <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} />
+                    </div>
+                    <div key="border" className="collectionFreeFormDocumentView-comic" >
+                        <svg style={{ overflow: "visible" }} viewBox={`0 0 ${pw} ${ph}`}>
+                            <path d={path} style={{ stroke: "black", fill: "transparent", strokeWidth: 3 }} />
+                        </svg>
+                    </div>
+                </>}
         </div>;
     }
 }
-- 
cgit v1.2.3-70-g09d2


From b7296ff9e0cf083ef1ae3423aa307e0dedf56f94 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 19 Apr 2021 16:10:19 -0400
Subject: more improvements to comic mode.

---
 src/client/util/CurrentUserUtils.ts                |  2 ++
 src/client/views/MainView.tsx                      |  7 +++----
 src/client/views/StyleProvider.tsx                 | 12 ++++++++++--
 .../collectionFreeForm/CollectionFreeFormView.tsx  |  2 +-
 .../nodes/CollectionFreeFormDocumentView.scss      |  6 ------
 .../views/nodes/CollectionFreeFormDocumentView.tsx | 22 ++--------------------
 src/client/views/nodes/DocumentView.scss           |  7 +++++++
 src/client/views/nodes/DocumentView.tsx            | 14 +++++++++++++-
 8 files changed, 38 insertions(+), 34 deletions(-)

(limited to 'src/client/views/nodes/CollectionFreeFormDocumentView.tsx')

diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index cb8bf5a7f..b1b7f8a09 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -1242,3 +1242,5 @@ Scripting.addGlobal(function links(doc: any) { return new List(LinkManager.Insta
     "returns all the links to the document or its annotations", "(doc: any)");
 Scripting.addGlobal(function importDocument() { return CurrentUserUtils.importDocument(); },
     "imports files from device directly into the import sidebar");
+Scripting.addGlobal(function toggleComicMode() { Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; },
+    "toggle between regular rendeing and an informal sketch/comic style");
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index fa2a738c8..e54d84a6c 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -180,8 +180,8 @@ export class MainView extends React.Component {
             const targClass = targets[0].className.toString();
             if (SearchBox.Instance._searchbarOpen || SearchBox.Instance.open) {
                 const check = targets.some((thing) =>
-                (thing.className === "collectionSchemaView-searchContainer" || (thing as any)?.dataset.icon === "filter" ||
-                    thing.className === "collectionSchema-header-menuOptions"));
+                    (thing.className === "collectionSchemaView-searchContainer" || (thing as any)?.dataset.icon === "filter" ||
+                        thing.className === "collectionSchema-header-menuOptions"));
                 !check && SearchBox.Instance.resetSearch(true);
             }
             !targClass.includes("contextMenu") && ContextMenu.Instance.closeMenu();
@@ -704,5 +704,4 @@ export class MainView extends React.Component {
     }
 }
 
-Scripting.addGlobal(function selectMainMenu(doc: Doc, title: string) { MainView.Instance.selectMenu(doc); });
-Scripting.addGlobal(function toggleComicMode() { Doc.UserDoc().fontFamily = "Comic Sans MS"; Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; });
\ No newline at end of file
+Scripting.addGlobal(function selectMainMenu(doc: Doc, title: string) { MainView.Instance.selectMenu(doc); });
\ No newline at end of file
diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx
index 0702f0d6b..a9fcd4717 100644
--- a/src/client/views/StyleProvider.tsx
+++ b/src/client/views/StyleProvider.tsx
@@ -41,6 +41,8 @@ export enum StyleProp {
     HeaderMargin = "headerMargin",        // margin at top of documentview, typically for displaying a title -- doc contents will start below that
     TitleHeight = "titleHeight",          // Height of Title area
     ShowTitle = "showTitle",              // whether to display a title on a Document (optional :hover suffix)
+    JitterRotation = "jitterRotation",    // whether documents should be randomly rotated
+    BorderPath = "customBorder",          // border path for document view
 }
 
 function darkScheme() { return BoolCast(CurrentUserUtils.ActiveDashboard?.darkScheme); }
@@ -60,7 +62,10 @@ export function testDocProps(toBeDetermined: any): toBeDetermined is DocumentVie
     return (toBeDetermined?.isContentActive) ? toBeDetermined : undefined;
 }
 
-//
+function wavyBorderPath(pw: number, ph: number) {
+    return `M ${pw * .5} ${ph * .05}   C ${pw * .6} ${ph * .05} ${pw * .9} 0 ${pw * .95} ${ph * .05}   C ${pw} ${ph * .1} ${pw * .95} ${ph * .2} ${pw * .95} ${ph * .25}   C ${pw * .95} ${ph * .35} ${pw} ${ph * .9} ${pw * .95} ${ph * .95}  C ${pw * .9} ${ph} ${pw * .6} ${ph * .95} ${pw * .5} ${ph * .95}   C ${pw * .3} ${ph * .95} ${pw * .1} ${ph} ${pw * .05} ${ph * .95}  C 0 ${ph * .9} ${pw * .05} ${ph * .85} ${pw * .05} ${ph * .8}   C ${pw * .05} ${ph * .75} 0 ${ph * .1} ${pw * .05} ${ph * .05}   C ${pw * .1} 0 ${pw * .25} ${ph * .05} ${pw * .5} ${ph * .05}`;
+}
+
 // a preliminary implementation of a dash style sheet for setting rendering properties of documents nested within a Tab
 // 
 export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps>, property: string): any {
@@ -71,11 +76,12 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
     const isAnchor = property.includes(":anchor");
     const isAnnotated = property.includes(":annotated");
     const isOpen = property.includes(":open");
+    const comicStyle = () => doc && !Doc.IsSystem(doc) && Doc.UserDoc().renderStyle === "comic";
     const isBackground = () => StrListCast(doc?._layerTags).includes(StyleLayers.Background);
     const backgroundCol = () => props?.styleProvider?.(doc, props, StyleProp.BackgroundColor);
     const opacity = () => props?.styleProvider?.(doc, props, StyleProp.Opacity);
     const showTitle = () => props?.styleProvider?.(doc, props, StyleProp.ShowTitle);
-
+    const random = (min: number, max: number, x: number, y: number) => { /* min should not be equal to max */ return min + ((Math.abs(x * y) * 9301 + 49297) % 233280 / 233280) * (max - min); }
     switch (property.split(":")[0]) {
         case StyleProp.TreeViewIcon: return Doc.toIcon(doc, isOpen);
         case StyleProp.DocContents: return undefined;
@@ -98,6 +104,8 @@ export function DefaultStyleProvider(doc: Opt<Doc>, props: Opt<DocumentViewProps
         case StyleProp.Hidden: return BoolCast(doc?._hidden);
         case StyleProp.BorderRounding: return StrCast(doc?.[fieldKey + "borderRounding"], StrCast(doc?._borderRounding));
         case StyleProp.TitleHeight: return 15;
+        case StyleProp.BorderPath: return comicStyle() ? { path: wavyBorderPath(props?.PanelWidth?.() || 0, props?.PanelHeight?.() || 0), width: 3 } : { path: undefined, width: 0 };
+        case StyleProp.JitterRotation: return comicStyle() ? random(-1, 1, NumCast(doc?.x), NumCast(doc?.y)) * ((props?.PanelWidth() || 0) > (props?.PanelHeight() || 0) ? 5 : 10) : 0;
         case StyleProp.HeaderMargin: return ([CollectionViewType.Stacking, CollectionViewType.Masonry].includes(doc?._viewType as any) ||
             doc?.type === DocumentType.RTF) && showTitle() && !StrCast(doc?.showTitle).includes(":hover") ? 15 : 0;
         case StyleProp.BackgroundColor: {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 7a879ecde..407216217 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1051,7 +1051,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
             dontRegisterView={this.props.dontRegisterView}
             pointerEvents={this.backgroundActive || this.props.childPointerEvents ? "all" :
                 (this.props.viewDefDivClick || (engine === "pass" && !this.props.isSelected(true))) ? "none" : undefined}
-            jitterRotation={NumCast(this.props.Document._jitterRotation) || ((Doc.UserDoc().renderStyle === "comic" ? 10 : 0))}
+            jitterRotation={this.props.styleProvider?.(childLayout, this.props, StyleProp.JitterRotation) || 0}
         //fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)} // bcz: check this
         />;
     }
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.scss b/src/client/views/nodes/CollectionFreeFormDocumentView.scss
index 98208c2a6..724394025 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.scss
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.scss
@@ -6,10 +6,4 @@
     top: 0;
     left: 0;
     pointer-events: none;
-    .collectionFreeFormDocumentView-comic {
-        width:100%;
-        height: 100%;
-        position: absolute;
-        top: 0;
-    }
 }
\ No newline at end of file
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index 807a61094..092823603 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -37,14 +37,9 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     public static animFields = ["_height", "_width", "x", "y", "_scrollTop", "opacity"];  // fields that are configured to be animatable using animation frames
     @observable _animPos: number[] | undefined = undefined;
     @observable _contentView: DocumentView | undefined | null;
-    @computed get jitterRotation() {
-        const rot = this.random(-1, 1) * this.props.jitterRotation * (this.props.PanelWidth() > this.props.PanelHeight() ? 0.5 : 1);
-        return rot;
-    }
-    random(min: number, max: number) { /* min should not be equal to max */ return min + ((Math.abs(this.X * this.Y) * 9301 + 49297) % 233280 / 233280) * (max - min); }
     get displayName() { return "CollectionFreeFormDocumentView(" + this.rootDoc.title + ")"; } // this makes mobx trace() statements more descriptive
     get maskCentering() { return this.props.Document.isInkMask ? InkingStroke.MaskDim / 2 : 0; }
-    get transform() { return `translate(${this.X - this.maskCentering}px, ${this.Y - this.maskCentering}px) rotate(${this.jitterRotation}deg)`; }
+    get transform() { return `translate(${this.X - this.maskCentering}px, ${this.Y - this.maskCentering}px) rotate(${this.props.jitterRotation}deg)`; }
     get X() { return this.dataProvider ? this.dataProvider.x : (this.Document.x || 0); }
     get Y() { return this.dataProvider ? this.dataProvider.y : (this.Document.y || 0); }
     get ZInd() { return this.dataProvider ? this.dataProvider.zIndex : (this.Document.zIndex || 0); }
@@ -160,9 +155,6 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
     returnThis = () => this;
     render() {
         TraceMobx();
-        const pw = this.panelWidth();
-        const ph = this.panelHeight();
-        const path = `M ${pw * .5} ${ph * .05}   C ${pw * .6} ${ph * .05} ${pw * .9} 0 ${pw * .95} ${ph * .05}   C ${pw} ${ph * .1} ${pw * .95} ${ph * .2} ${pw * .95} ${ph * .25}   C ${pw * .95} ${ph * .35} ${pw} ${ph * .9} ${pw * .95} ${ph * .95}  C ${pw * .9} ${ph} ${pw * .6} ${ph * .95} ${pw * .5} ${ph * .95}   C ${pw * .3} ${ph * .95} ${pw * .1} ${ph} ${pw * .05} ${ph * .95}  C 0 ${ph * .9} ${pw * .05} ${ph * .85} ${pw * .05} ${ph * .8}   C ${pw * .05} ${ph * .75} 0 ${ph * .1} ${pw * .05} ${ph * .05}   C ${pw * .1} 0 ${pw * .25} ${ph * .05} ${pw * .5} ${ph * .05}`;
         const divProps: DocumentViewProps = {
             ...this.props,
             CollectionFreeFormDocumentView: this.returnThis,
@@ -183,17 +175,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
                 mixBlendMode: StrCast(this.layoutDoc.mixBlendMode) as any,
                 display: this.ZInd === -99 ? "none" : undefined
             }} >
-            {Doc.UserDoc().renderStyle !== "comic" ? <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} /> :
-                <>
-                    <div key="doc" style={{ clipPath: `path('${path}')` }}>
-                        <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} />
-                    </div>
-                    <div key="border" className="collectionFreeFormDocumentView-comic" >
-                        <svg style={{ overflow: "visible" }} viewBox={`0 0 ${pw} ${ph}`}>
-                            <path d={path} style={{ stroke: "black", fill: "transparent", strokeWidth: 3 }} />
-                        </svg>
-                    </div>
-                </>}
+            <DocumentView {...divProps} ref={action((r: DocumentView | null) => this._contentView = r)} />
         </div>;
     }
 }
diff --git a/src/client/views/nodes/DocumentView.scss b/src/client/views/nodes/DocumentView.scss
index 36572b861..bdbece621 100644
--- a/src/client/views/nodes/DocumentView.scss
+++ b/src/client/views/nodes/DocumentView.scss
@@ -4,6 +4,13 @@
     border-radius: inherit;
 }
 
+.documentView-customBorder {
+    width:100%;
+    height: 100%;
+    position: absolute;
+    top: 0;
+}
+
 .documentView-node,
 .documentView-node-topmost {
     position: inherit;
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 01b83644e..810868c75 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -978,6 +978,8 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
         let highlighting = !this.props.disableDocBrushing && highlightIndex && !excludeTypes.includes(this.layoutDoc.type as any) && this.layoutDoc._viewType !== CollectionViewType.Linear;
         highlighting = highlighting && this.props.focus !== emptyFunction && this.layoutDoc.title !== "[pres element template]";  // bcz: hack to turn off highlighting onsidebar panel documents.  need to flag a document as not highlightable in a more direct way
 
+        const borderPath = this.props.styleProvider?.(this.props.Document, this.props, StyleProp.BorderPath) || { path: undefined };
+        const internal = PresBox.EffectsProvider(this.layoutDoc, this.renderDoc) || this.renderDoc;
         const boxShadow = highlighting && this.borderRounding && highlightStyle !== "dashed" ? `0 0 0 ${highlightIndex}px ${highlightColor}` :
             this.boxShadow || (this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined);
         return <div className={DocumentView.ROOT_DIV} ref={this._mainCont}
@@ -993,8 +995,18 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 outline: highlighting && !this.borderRounding ? `${highlightColor} ${highlightStyle} ${highlightIndex}px` : "solid 0px",
                 border: highlighting && this.borderRounding && highlightStyle === "dashed" ? `${highlightStyle} ${highlightColor} ${highlightIndex}px` : undefined,
                 boxShadow,
+                clipPath: `path('${borderPath.path}')`,
             }}>
-            {PresBox.EffectsProvider(this.layoutDoc, this.renderDoc) || this.renderDoc}
+            {!borderPath.path ? internal :
+                <>
+                    {internal}
+                    <div key="border" className="documentView-customBorder" style={{ pointerEvents: "none" }} >
+                        <svg style={{ overflow: "visible" }} viewBox={`0 0 ${this.props.PanelWidth()} ${this.props.PanelHeight()}`}>
+                            <path d={borderPath.path} style={{ stroke: "black", fill: "transparent", strokeWidth: borderPath.width }} />
+                        </svg>
+                    </div>
+                </>
+            }
         </div>;
     }
 }
-- 
cgit v1.2.3-70-g09d2

