From fd5278045e8c2e280d81cb965c0b2cc5afb59be8 Mon Sep 17 00:00:00 2001
From: eleanor-park <eleanor_park@brown.edu>
Date: Wed, 7 Aug 2024 18:09:47 -0400
Subject: problem with setting smooth amount

---
 src/client/views/PropertiesView.tsx | 180 +++++++++++++++++++++++++++++++++---
 1 file changed, 166 insertions(+), 14 deletions(-)

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

diff --git a/src/client/views/PropertiesView.tsx b/src/client/views/PropertiesView.tsx
index 024db82a4..ac2625f32 100644
--- a/src/client/views/PropertiesView.tsx
+++ b/src/client/views/PropertiesView.tsx
@@ -5,7 +5,7 @@ import { IconLookup } from '@fortawesome/fontawesome-svg-core';
 import { faAnchor, faArrowRight, faWindowMaximize } from '@fortawesome/free-solid-svg-icons';
 import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
 import { Checkbox, Tooltip } from '@mui/material';
-import { Colors, EditableText, IconButton, NumberInput, Size, Slider, Type } from 'browndash-components';
+import { Colors, EditableText, IconButton, NumberInput, Size, Slider, Toggle, ToggleType, Type } from 'browndash-components';
 import { concat } from 'lodash';
 import { IReactionDisposer, action, computed, makeObservable, observable, reaction } from 'mobx';
 import { observer } from 'mobx-react';
@@ -14,13 +14,13 @@ import { ColorResult, SketchPicker } from 'react-color';
 import * as Icons from 'react-icons/bs'; // {BsCollectionFill, BsFillFileEarmarkImageFill} from "react-icons/bs"
 import { ClientUtils, returnEmptyDoclist, returnEmptyFilter, returnEmptyString, returnFalse, returnTrue, setupMoveUpEvents } from '../../ClientUtils';
 import { emptyFunction } from '../../Utils';
-import { Doc, Field, FieldResult, FieldType, HierarchyMapping, NumListCast, Opt, ReverseHierarchyMap, StrListCast } from '../../fields/Doc';
+import { Doc, DocListCast, Field, FieldResult, FieldType, HierarchyMapping, NumListCast, Opt, ReverseHierarchyMap, StrListCast } from '../../fields/Doc';
 import { AclAdmin, DocAcl, DocData } from '../../fields/DocSymbols';
 import { Id } from '../../fields/FieldSymbols';
 import { InkField } from '../../fields/InkField';
 import { List } from '../../fields/List';
 import { ComputedField } from '../../fields/ScriptField';
-import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types';
+import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types';
 import { GetEffectiveAcl, SharingPermissions, normalizeEmail } from '../../fields/util';
 import { CollectionViewType, DocumentType } from '../documents/DocumentTypes';
 import { GroupManager } from '../util/GroupManager';
@@ -43,6 +43,10 @@ import { DocumentView } from './nodes/DocumentView';
 import { StyleProviderFuncType } from './nodes/FieldView';
 import { OpenWhere } from './nodes/OpenWhere';
 import { PresBox, PresEffect, PresEffectDirection } from './nodes/trails';
+import { InkingStroke } from './InkingStroke';
+import { SettingsManager } from '../util/SettingsManager';
+import { MarqueeOptionsMenu } from './collections/collectionFreeForm';
+import { SmartDrawHandler } from './smartdraw/SmartDrawHandler';
 
 const _global = (window /* browser */ || global) /* node */ as any;
 
@@ -117,6 +121,10 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
     @observable openAddSlide: boolean = false;
     @observable openSlideOptions: boolean = false;
 
+    // For ink groups
+    @observable containsInkDoc: boolean = false;
+    @observable inkDoc: Doc | undefined = undefined;
+
     @observable _controlButton: boolean = false;
     private _disposers: { [name: string]: IReactionDisposer } = {};
 
@@ -794,7 +802,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
     };
 
     getField(key: string) {
-        return Field.toString(this.selectedDoc?.[DocData][key] as FieldType);
+        return this.containsInkDoc ? Field.toString(this.inkDoc?.[DocData][key] as FieldType) : Field.toString(this.selectedDoc?.[DocData][key] as FieldType);
     }
 
     @computed get shapeXps() { return NumCast(this.selectedDoc?.x); } // prettier-ignore
@@ -805,8 +813,17 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
     set shapeWid(value)  { this.selectedDoc && (this.selectedDoc._width = Math.round(value * 100) / 100); } // prettier-ignore
     @computed get shapeHgt() { return NumCast(this.selectedDoc?._height); } // prettier-ignore
     set shapeHgt(value)  { this.selectedDoc && (this.selectedDoc._height = Math.round(value * 100) / 100); } // prettier-ignore
-    @computed get strokeThk(){ return NumCast(this.selectedDoc?.[DocData].stroke_width); } // prettier-ignore
-    set strokeThk(value) { this.selectedDoc && (this.selectedDoc[DocData].stroke_width = Math.round(value * 100) / 100); } // prettier-ignore
+    @computed get strokeThk(){ return this.containsInkDoc ?  NumCast(this.inkDoc?.[DocData].stroke_width) : NumCast(this.selectedDoc?.[DocData].stroke_width); } // prettier-ignore
+    set strokeThk(value) { 
+        if (this.containsInkDoc) {
+            const childDocs = DocListCast(this.selectedDoc[DocData].data);
+            childDocs.forEach(doc => {
+                doc[DocData].stroke_width = Math.round(value * 100) / 100;
+            })
+        } else {
+            this.selectedDoc && (this.selectedDoc[DocData].stroke_width = Math.round(value * 100) / 100); 
+        }
+    } // prettier-ignore
 
     @computed get hgtInput() {
         return this.inputBoxDuo(
@@ -843,10 +860,32 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
 
     private _lastDash: any = '2';
 
-    @computed get colorFil() { return StrCast(this.selectedDoc?.[DocData].fillColor); } // prettier-ignore
-    set colorFil(value) { this.selectedDoc && (this.selectedDoc[DocData].fillColor = value || undefined); } // prettier-ignore
-    @computed get colorStk() { return StrCast(this.selectedDoc?.[DocData].color); } // prettier-ignore
-    set colorStk(value) { this.selectedDoc && (this.selectedDoc[DocData].color = value || undefined); } // prettier-ignore
+    @computed get colorFil() { return this.containsInkDoc ? StrCast(this.inkDoc?.[DocData].fillColor) : StrCast(this.selectedDoc?.[DocData].fillColor); } // prettier-ignore
+    set colorFil(value) {
+        if (this.containsInkDoc) {
+            const childDocs = DocListCast(this.selectedDoc[DocData].data);
+            childDocs.forEach(doc => {
+                const inkStroke = DocumentView.getDocumentView(doc)?.ComponentView as InkingStroke;
+                const { inkData } = inkStroke.inkScaledData();
+                if (InkingStroke.IsClosed(inkData)) {
+                    doc[DocData].fillColor = value || undefined;
+                }
+            });
+        } else {
+            this.selectedDoc && (this.selectedDoc[DocData].fillColor = value || undefined);
+        }
+    }
+    @computed get colorStk() { return this.containsInkDoc ? StrCast(this.inkDoc?.[DocData].color) : StrCast(this.selectedDoc?.[DocData].color); } // prettier-ignore
+    set colorStk(value) {
+        if (this.containsInkDoc) {
+            const childDocs = DocListCast(this.selectedDoc[DocData].data);
+            childDocs.forEach(doc => {
+                doc[DocData].color = value || undefined;
+            });
+        } else {
+            this.selectedDoc && (this.selectedDoc[DocData].color = value || undefined);
+        }
+    }
 
     colorButton(value: string, type: string, setter: () => void) {
         return (
@@ -917,10 +956,69 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
         );
     }
 
-    @computed get dashdStk() {  return this.selectedDoc?.stroke_dash || ''; } // prettier-ignore
+    @computed get smoothAndColor() {
+        const targetDoc = this.selectedLayoutDoc;
+        return (
+            <div>
+                <div className="smooth">
+                    <Toggle
+                        text={'Smooth Ink Strokes'}
+                        color={SettingsManager.userColor}
+                        icon={<FontAwesomeIcon icon="bezier-curve" />}
+                        iconPlacement="left"
+                        align="flex-start"
+                        fillWidth
+                        toggleType={ToggleType.BUTTON}
+                        onClick={undoable(() => {
+                            InkStrokeProperties.Instance.smoothInkStrokes(this.containsInkDoc ? DocListCast(targetDoc.data) : [targetDoc], this.smoothAmt);
+                        }, 'smoothStrokes')}
+                    />
+                </div>
+                <div className="smooth-slider">
+                    {this.getNumber(
+                        'Smooth Amount',
+                        '',
+                        1,
+                        Math.max(20, this.smoothAmt),
+                        this.smoothAmt,
+                        (val: number) => {
+                            !isNaN(val) && (this.smoothAmt = val);
+                        },
+                        20,
+                        1
+                    )}
+                </div>
+                {!targetDoc.layout_isSvg && (
+                    <div className="color">
+                        <Toggle
+                            text={'Color with GPT'}
+                            color={SettingsManager.userColor}
+                            icon={<FontAwesomeIcon icon="fill-drip" />}
+                            iconPlacement="left"
+                            align="flex-start"
+                            fillWidth
+                            toggleType={ToggleType.BUTTON}
+                            onClick={undoable(() => {
+                                SmartDrawHandler.Instance.colorWithGPT(targetDoc);
+                            }, 'smoothStrokes')}
+                        />
+                    </div>
+                )}
+            </div>
+        );
+    }
+
+    @computed get dashdStk() {  return this.containsInkDoc? this.inkDoc?.stroke_dash || '' : this.selectedDoc?.stroke_dash || ''; } // prettier-ignore
     set dashdStk(value) {
         value && (this._lastDash = value);
-        this.selectedDoc && (this.selectedDoc[DocData].stroke_dash = value ? this._lastDash : undefined);
+        if (this.containsInkDoc) {
+            const childDocs = DocListCast(this.selectedDoc[DocData].data);
+            childDocs.forEach(doc => {
+                doc[DocData].stroke_dash = value ? this._lastDash : undefined;
+            });
+        } else {
+            this.selectedDoc && (this.selectedDoc[DocData].stroke_dash = value ? this._lastDash : undefined);
+        }
     }
     @computed get widthStk() { return this.getField('stroke_width') || '1'; } // prettier-ignore
     set widthStk(value) {
@@ -930,13 +1028,31 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
     set markScal(value) {
         this.selectedDoc && (this.selectedDoc[DocData].stroke_markerScale = Number(value));
     }
+    @computed get smoothAmt() { return Number(this.getField('stroke_smoothAmount') || '1'); } // prettier-ignore
+    set smoothAmt(value) {
+        this.selectedDoc && (this.selectedDoc[DocData].stroke_smoothAmount = Number(value));
+    }
     @computed get markHead() { return this.getField('stroke_startMarker') || ''; } // prettier-ignore
     set markHead(value) {
-        this.selectedDoc && (this.selectedDoc[DocData].stroke_startMarker = value);
+        if (this.containsInkDoc) {
+            const childDocs = DocListCast(this.selectedDoc[DocData].data);
+            childDocs.forEach(doc => {
+                doc[DocData].stroke_startMarker = value;
+            });
+        } else {
+            this.selectedDoc && (this.selectedDoc[DocData].stroke_startMarker = value);
+        }
     }
     @computed get markTail() {  return this.getField('stroke_endMarker') || ''; } // prettier-ignore
     set markTail(value) {
-        this.selectedDoc && (this.selectedDoc[DocData].stroke_endMarker = value);
+        if (this.containsInkDoc) {
+            const childDocs = DocListCast(this.selectedDoc[DocData].data);
+            childDocs.forEach(doc => {
+                doc[DocData].stroke_endMarker = value;
+            });
+        } else {
+            this.selectedDoc && (this.selectedDoc[DocData].stroke_endMarker = value);
+        }
     }
 
     regInput = (key: string, value: any, setter: (val: string) => {}) => (
@@ -1036,6 +1152,16 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
             <div className="appearance-editor">
                 {this.widthAndDash}
                 {this.strokeAndFill}
+                {this.smoothAndColor}
+            </div>
+        );
+    }
+
+    @computed get inkEditor() {
+        return (
+            <div className="ink-editor">
+                {this.widthAndDash}
+                {this.strokeAndFill}
             </div>
         );
     }
@@ -1164,6 +1290,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
     }
 
     @computed get inkSubMenu() {
+        this.containsInkDoc = false;
         return (
             // prettier-ignore
             <>
@@ -1177,6 +1304,30 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
         );
     }
 
+    containsInk = (selectedDoc: Doc) => {
+        const childDocs: Doc[] = DocListCast(selectedDoc[DocData].data);
+        for (var i = 0; i < childDocs.length; i++) {
+            if (DocumentView.getDocumentView(childDocs[i])?.layoutDoc?.layout_isSvg) {
+                this.inkDoc = childDocs[i];
+                this.containsInkDoc = true;
+                return true;
+            }
+        }
+        this.containsInkDoc = false;
+        return false;
+    };
+
+    @computed get inkCollectionSubMenu() {
+        return (
+            // prettier-ignore
+            <>
+                <PropertiesSection title="Ink Appearance" isOpen={this.openAppearance} setIsOpen={bool => { this.openAppearance = bool; }} onDoubleClick={this.CloseAll}>
+                    {this.isGroup && this.containsInk(this.selectedDoc) ? this.appearanceEditor : null}
+                </PropertiesSection>
+            </>
+        );
+    }
+
     @computed get fieldsSubMenu() {
         return (
             <PropertiesSection
@@ -1737,6 +1888,7 @@ export class PropertiesView extends ObservableReactComponent<PropertiesViewProps
                     {this.linksSubMenu}
                     {!this.selectedLink || !this.openLinks ? null : this.linkProperties}
                     {this.inkSubMenu}
+                    {this.inkCollectionSubMenu}
                     {this.contextsSubMenu}
                     {isNovice ? null : this.sharingSubMenu}
                     {this.filtersSubMenu}
-- 
cgit v1.2.3-70-g09d2

