diff options
| author | usodhi <61431818+usodhi@users.noreply.github.com> | 2020-07-06 15:33:45 +0530 |
|---|---|---|
| committer | usodhi <61431818+usodhi@users.noreply.github.com> | 2020-07-06 15:33:45 +0530 |
| commit | b442fc347abc267697575c517949ca0ee0dad2f1 (patch) | |
| tree | fe5e0aca9dbf155196b0e8514cdcadbfc26dc36d /src/client/views/collections/collectionFreeForm | |
| parent | 94137cb3a771ec6afd803f3cff97da86a14dd54f (diff) | |
| parent | 6b24899bcf2c099163c1ca872d65b6318c11a53b (diff) | |
Merge branch 'master' of https://github.com/browngraphicslab/Dash-Web into grid_view_secondary
Diffstat (limited to 'src/client/views/collections/collectionFreeForm')
6 files changed, 306 insertions, 80 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx index ae81b4b36..1a2421bfd 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinksView.tsx @@ -10,6 +10,7 @@ import React = require("react"); import { Utils, emptyFunction } from "../../../../Utils"; import { DocumentType } from "../../../documents/DocumentTypes"; import { SnappingManager } from "../../../util/SnappingManager"; +import { Cast } from "../../../../fields/Types"; @observer export class CollectionFreeFormLinksView extends React.Component { @@ -30,8 +31,8 @@ export class CollectionFreeFormLinksView extends React.Component { return drawnPairs; }, [] as { a: DocumentView, b: DocumentView, l: Doc[] }[]); return connections.filter(c => - c.a.props.Document.type === DocumentType.LINK && - c.a.props.pinToPres !== emptyFunction && c.b.props.pinToPres !== emptyFunction // bcz: this prevents links to be drawn to anchors in CollectionTree views -- this is a hack that should be fixed + c.a.props.Document.type === DocumentType.LINK + && !c.a.props.treeViewDoc?.treeViewHideLinkLines && !c.b.props.treeViewDoc?.treeViewHideLinkLines ).map(c => <CollectionFreeFormLinkView key={Utils.GenerateGuid()} A={c.a} B={c.b} LinkDocs={c.l} />); } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index d9011c9d3..92aee3776 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -1,7 +1,6 @@ @import "../../globalCssVariables"; -.collectionfreeformview-none, -.collectionfreeformview-ease { +.collectionfreeformview-none { position: inherit; top: 0; left: 0; @@ -22,10 +21,6 @@ } } -.collectionfreeformview-ease { - transition: transform 500ms; -} - .collectionfreeformview-none { touch-action: none; } diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 936174b52..b81e400b3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,53 +1,51 @@ import { library } from "@fortawesome/fontawesome-svg-core"; -import { faEye, faEyeSlash } from "@fortawesome/free-regular-svg-icons"; +import { faEye } from "@fortawesome/free-regular-svg-icons"; import { faBraille, faChalkboard, faCompass, faCompressArrowsAlt, faExpandArrowsAlt, faFileUpload, faPaintBrush, faTable, faUpload } from "@fortawesome/free-solid-svg-icons"; -import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction, _allowStateChangesInsideComputed, trace } from "mobx"; +import { action, computed, IReactionDisposer, observable, ObservableMap, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; import { computedFn } from "mobx-utils"; -import { Doc, HeightSym, Opt, WidthSym, DocListCast } from "../../../../fields/Doc"; -import { documentSchema, collectionSchema } from "../../../../fields/documentSchemas"; +import { Doc, DocListCast, HeightSym, Opt, WidthSym } from "../../../../fields/Doc"; +import { collectionSchema, documentSchema } from "../../../../fields/documentSchemas"; import { Id } from "../../../../fields/FieldSymbols"; -import { InkData, InkField, InkTool, PointData } from "../../../../fields/InkField"; +import { InkData, InkField, InkTool } from "../../../../fields/InkField"; import { List } from "../../../../fields/List"; import { RichTextField } from "../../../../fields/RichTextField"; -import { createSchema, listSpec, makeInterface } from "../../../../fields/Schema"; -import { ScriptField, ComputedField } from "../../../../fields/ScriptField"; +import { createSchema, makeInterface } from "../../../../fields/Schema"; +import { ScriptField } from "../../../../fields/ScriptField"; import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; import { TraceMobx } from "../../../../fields/util"; import { GestureUtils } from "../../../../pen-gestures/GestureUtils"; -import { aggregateBounds, intersectRect, returnOne, Utils, returnZero, returnFalse, numberRange } from "../../../../Utils"; +import { aggregateBounds, intersectRect, returnFalse, returnOne, returnZero, Utils } from "../../../../Utils"; import { CognitiveServices } from "../../../cognitive_services/CognitiveServices"; import { DocServer } from "../../../DocServer"; import { Docs, DocUtils } from "../../../documents/Documents"; +import { DocumentType } from "../../../documents/DocumentTypes"; import { DocumentManager } from "../../../util/DocumentManager"; import { DragManager, dropActionType } from "../../../util/DragManager"; import { HistoryUtil } from "../../../util/History"; import { InteractionUtils } from "../../../util/InteractionUtils"; import { SelectionManager } from "../../../util/SelectionManager"; +import { SnappingManager } from "../../../util/SnappingManager"; import { Transform } from "../../../util/Transform"; import { undoBatch, UndoManager } from "../../../util/UndoManager"; import { COLLECTION_BORDER_WIDTH } from "../../../views/globalCssVariables.scss"; +import { Timeline } from "../../animationtimeline/Timeline"; import { ContextMenu } from "../../ContextMenu"; -import { ContextMenuProps } from "../../ContextMenuItem"; +import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth } from "../../InkingStroke"; import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView"; -import { DocumentViewProps, DocumentView } from "../../nodes/DocumentView"; +import { DocumentLinksButton } from "../../nodes/DocumentLinksButton"; +import { DocumentViewProps } from "../../nodes/DocumentView"; import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox"; import { pageSchema } from "../../nodes/ImageBox"; -import PDFMenu from "../../pdf/PDFMenu"; import { CollectionDockingView } from "../CollectionDockingView"; import { CollectionSubView } from "../CollectionSubView"; -import { computePivotLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult, computerStarburstLayout, computerPassLayout } from "./CollectionFreeFormLayoutEngines"; +import { CollectionViewType } from "../CollectionView"; +import { computePivotLayout, computerPassLayout, computerStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from "./CollectionFreeFormLayoutEngines"; import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors"; import "./CollectionFreeFormView.scss"; import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import { MarqueeView } from "./MarqueeView"; import React = require("react"); -import { CollectionViewType } from "../CollectionView"; -import { Timeline } from "../../animationtimeline/Timeline"; -import { SnappingManager } from "../../../util/SnappingManager"; -import { ActiveInkColor, ActiveInkWidth, ActiveInkBezierApprox } from "../../InkingStroke"; -import { DocumentType } from "../../../documents/DocumentTypes"; -import { DocumentLinksButton } from "../../nodes/DocumentLinksButton"; library.add(faEye as any, faTable, faPaintBrush, faExpandArrowsAlt, faCompressArrowsAlt, faCompass, faUpload, faBraille, faChalkboard, faFileUpload); @@ -63,7 +61,7 @@ export const panZoomSchema = createSchema({ fitToBox: "boolean", _xPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set _yPadding: "number", // pixels of padding on left/right of collectionfreeformview contents when fitToBox is set - panTransformType: "string", + _viewTransition: "string", scrollHeight: "number", fitX: "number", fitY: "number", @@ -110,9 +108,8 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P @computed get nativeWidth() { return this.fitToContent ? 0 : NumCast(this.Document._nativeWidth, this.props.NativeWidth()); } @computed get nativeHeight() { return this.fitToContent ? 0 : NumCast(this.Document._nativeHeight, this.props.NativeHeight()); } private get isAnnotationOverlay() { return this.props.isAnnotationOverlay; } - private get scaleFieldKey() { return this.props.scaleField || "scale"; } + private get scaleFieldKey() { return this.props.scaleField || "_viewScale"; } private get borderWidth() { return this.isAnnotationOverlay ? 0 : COLLECTION_BORDER_WIDTH; } - private easing = () => this.props.Document.panTransformType === "Ease"; private panX = () => this.fitToContent ? (this.contentBounds.x + this.contentBounds.r) / 2 : this.Document._panX || 0; private panY = () => this.fitToContent ? (this.contentBounds.y + this.contentBounds.b) / 2 : this.Document._panY || 0; private zoomScaling = () => (this.fitToContentScaling / this.parentScaling) * (this.fitToContent ? @@ -195,7 +192,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P return (pt => super.onExternalDrop(e, { x: pt[0], y: pt[1] }))(this.getTransform().transformPoint(e.pageX, e.pageY)); } - @undoBatch @action internalDocDrop(e: Event, de: DragManager.DropEvent, docDragData: DragManager.DocumentDragData, xp: number, yp: number) { if (!super.onInternalDrop(e, de)) return false; @@ -463,7 +459,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, + const inkDoc = Docs.Create.InkDocument(ActiveInkColor(), Doc.GetSelectedTool(), ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), points, { title: "ink stroke", x: B.x - Number(ActiveInkWidth()) / 2, y: B.y - Number(ActiveInkWidth()) / 2, _width: B.width + Number(ActiveInkWidth()), _height: B.height + Number(ActiveInkWidth()) }); this.addDocument(inkDoc); e.stopPropagation(); @@ -604,7 +600,6 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P pan = (e: PointerEvent | React.Touch | { clientX: number, clientY: number }): void => { // bcz: theres should be a better way of doing these than referencing these static instances directly MarqueeOptionsMenu.Instance?.fadeOut(true);// I think it makes sense for the marquee menu to go away when panned. -syip2 - PDFMenu.Instance.fadeOut(true); const [dx, dy] = this.getTransform().transformDirection(e.clientX - this._lastX, e.clientY - this._lastY); this.setPan((this.Document._panX || 0) - dx, (this.Document._panY || 0) - dy, undefined, true); @@ -832,7 +827,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P } } if (!this.layoutDoc._lockedTransform || this.Document.inOverlay) { - this.Document.panTransformType = panType; + this.Document._viewTransition = panType; const scale = this.getLocalTransform().inverse().Scale; const newPanX = Math.min((1 - 1 / scale) * this.nativeWidth, Math.max(0, panX)); const newPanY = Math.min((this.props.Document.scrollHeight !== undefined ? NumCast(this.Document.scrollHeight) : (1 - 1 / scale) * this.nativeHeight), Math.max(0, panY)); @@ -860,7 +855,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P scaleAtPt(docpt: number[], scale: number) { const screenXY = this.getTransform().inverse().transformPoint(docpt[0], docpt[1]); - this.Document.panTransformType = "Ease"; + this.Document._viewTransition = "transform 500ms"; this.layoutDoc[this.scaleFieldKey] = scale; const newScreenXY = this.getTransform().inverse().transformPoint(docpt[0], docpt[1]); const scrDelta = { x: screenXY[0] - newScreenXY[0], y: screenXY[1] - newScreenXY[1] }; @@ -872,7 +867,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P focusDocument = (doc: Doc, willZoom: boolean, scale?: number, afterFocus?: () => boolean) => { const state = HistoryUtil.getState(); - // TODO This technically isn't correct if type !== "doc", as + // TODO This technically isn't correct if type !== "doc", as // currently nothing is done, but we should probably push a new state if (state.type === "doc" && this.Document._panX !== undefined && this.Document._panY !== undefined) { const init = state.initializers![this.Document[Id]]; @@ -905,14 +900,14 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P newState.initializers![this.Document[Id]] = { panX: newPanX, panY: newPanY }; HistoryUtil.pushState(newState); - const savedState = { px: this.Document._panX, py: this.Document._panY, s: this.Document[this.scaleFieldKey], pt: this.Document.panTransformType }; + const savedState = { px: this.Document._panX, py: this.Document._panY, s: this.Document[this.scaleFieldKey], pt: this.Document._viewTransition }; // if (!willZoom && DocumentView._focusHack.length) { // Doc.BrushDoc(this.props.Document); // !doc.z && NumCast(this.layoutDoc.scale) < 1 && this.scaleAtPt(DocumentView._focusHack, 1); // [NumCast(doc.x), NumCast(doc.y)], 1); // } else { if (DocListCast(this.dataDoc[this.props.fieldKey]).includes(doc)) { - if (!doc.z) this.setPan(newPanX, newPanY, "Ease", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow + if (!doc.z) this.setPan(newPanX, newPanY, "transform 500ms", true); // docs that are floating in their collection can't be panned to from their collection -- need to propagate the pan to a parent freeform somehow } Doc.BrushDoc(this.props.Document); this.props.focus(this.props.Document); @@ -925,7 +920,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P this.Document._panX = savedState.px; this.Document._panY = savedState.py; this.Document[this.scaleFieldKey] = savedState.s; - this.Document.panTransformType = savedState.pt; + this.Document._viewTransition = savedState.pt; } }, 500); } @@ -1011,7 +1006,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P const { z, color, zIndex } = params.pair.layout; return { x: NumCast(x), y: NumCast(y), z: Cast(z, "number"), color: StrCast(color), zIndex: Cast(zIndex, "number"), - transition: StrCast(layoutDoc.transition), opacity: this.Document.editing ? 1 : Cast(opacity, "number", null), + transition: StrCast(layoutDoc.dataTransition), opacity: this.Document.editing ? 1 : Cast(opacity, "number", null), width: Cast(layoutDoc._width, "number"), height: Cast(layoutDoc._height, "number"), pair: params.pair, replica: "" }; } @@ -1206,7 +1201,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P private thumbIdentifier?: number; onContextMenu = (e: React.MouseEvent) => { - if (this.props.annotationsKey) return; + if (this.props.annotationsKey || !ContextMenu.Instance) return; const appearance = ContextMenu.Instance.findByDescription("Appearance..."); const appearanceItems = appearance && "subitems" in appearance ? appearance.subitems : []; @@ -1227,7 +1222,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P optionItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }); if (!Doc.UserDoc().noviceMode) { optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" }); - optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" }); + optionItems.push({ description: `${this.Document._freeformLOD ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._freeformLOD = !this.Document._freeformLOD, icon: "table" }); optionItems.push({ description: "Import document", icon: "upload", event: ({ x, y }) => { const input = document.createElement("input"); @@ -1333,9 +1328,9 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P nudge = action((x: number, y: number) => { if (this.props.ContainingCollectionDoc?._viewType !== CollectionViewType.Freeform) { // bcz: this isn't ideal, but want to try it out... this.setPan(NumCast(this.layoutDoc._panX) + this.props.PanelWidth() / 2 * x / this.zoomScaling(), - NumCast(this.layoutDoc._panY) + this.props.PanelHeight() / 2 * (-y) / this.zoomScaling(), "Ease", true); + NumCast(this.layoutDoc._panY) + this.props.PanelHeight() / 2 * (-y) / this.zoomScaling(), "transform 500ms", true); this._nudgeTime = Date.now(); - setTimeout(() => (Date.now() - this._nudgeTime >= 500) && (this.Document.panTransformType = undefined), 500); + setTimeout(() => (Date.now() - this._nudgeTime >= 500) && (this.Document._viewTransition = undefined), 500); return true; } return false; @@ -1354,8 +1349,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P <CollectionFreeFormViewPannableContents centeringShiftX={this.centeringShiftX} centeringShiftY={this.centeringShiftY} - easing={this.easing} - transition={Cast(this.layoutDoc.transition, "string", null)} + transition={Cast(this.layoutDoc._viewTransition, "string", null)} viewDefDivClick={this.props.viewDefDivClick} zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}> {this.children} @@ -1383,9 +1377,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P onPointerDown={this.onPointerDown} onPointerMove={this.onCursorMove} onDrop={this.onExternalDrop.bind(this)} - onDragOver={e => { - e.preventDefault(); - }} + onDragOver={e => e.preventDefault()} onContextMenu={this.onContextMenu} style={{ pointerEvents: this.backgroundEvents ? "all" : undefined, @@ -1394,7 +1386,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P width: this.contentScaling ? `${100 / this.contentScaling}%` : "", height: this.contentScaling ? `${100 / this.contentScaling}%` : this.isAnnotationOverlay ? (this.props.Document.scrollHeight ? this.Document.scrollHeight : "100%") : this.props.PanelHeight() }}> - {!this.Document._LODdisable && !this.props.active() && !this.props.isAnnotationOverlay && !this.props.annotationsKey && this.props.renderDepth > 0 ? + {this.Document._freeformLOD && !this.props.active() && !this.props.isAnnotationOverlay && !this.props.annotationsKey && this.props.renderDepth > 0 ? this.placeholder : this.marqueeView} <CollectionFreeFormOverlayView elements={this.elementFunc} /> @@ -1436,7 +1428,6 @@ interface CollectionFreeFormViewPannableContentsProps { panX: () => number; panY: () => number; zoomScaling: () => number; - easing: () => boolean; viewDefDivClick?: ScriptField; children: () => JSX.Element[]; transition?: string; @@ -1445,7 +1436,7 @@ interface CollectionFreeFormViewPannableContentsProps { @observer class CollectionFreeFormViewPannableContents extends React.Component<CollectionFreeFormViewPannableContentsProps>{ render() { - const freeformclass = "collectionfreeformview" + (this.props.viewDefDivClick ? "-viewDef" : (this.props.easing() ? "-ease" : "-none")); + const freeformclass = "collectionfreeformview" + (this.props.viewDefDivClick ? "-viewDef" : "-none"); const cenx = this.props.centeringShiftX(); const ceny = this.props.centeringShiftY(); const panx = -this.props.panX(); @@ -1459,4 +1450,4 @@ class CollectionFreeFormViewPannableContents extends React.Component<CollectionF {this.props.children()} </div>; } -}
\ No newline at end of file +} diff --git a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss index a7f4d4e53..753de6bef 100644 --- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss +++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.scss @@ -1,9 +1,13 @@ .antimodeMenu-button { - .color-preview { + .color-previewI { width: 100%; - height: 100%; + height: 40%; } + .color-previewII { + width: 100%; + height: 100%; + } } @@ -31,6 +35,44 @@ background: #323232; display: block; + } +} + +@media only screen and (max-device-width: 480px) { + .antimodeMenu-button { + font-size: 50%; + + .color-preview { + width: 100%; + height: 100%; + } + + } + + .sketch-picker { + background: #323232; + + .flexbox-fit { + background: #323232; + } + } + + .btn-group { + display: grid; + grid-template-columns: auto auto; + /* Make the buttons appear below each other */ + } + + .btn2-group { + display: block; + background: #323232; + grid-template-columns: auto; + /* Make the buttons appear below each other */ + .antimodeMenu-button { + background: #323232; + display: block; + font-size: 50%; + } } }
\ 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 4fac87ca5..f47fca6ac 100644 --- a/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx +++ b/src/client/views/collections/collectionFreeForm/InkOptionsMenu.tsx @@ -3,25 +3,48 @@ 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"; +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"]; - private _width = ["1", "5", "10", "100", "200", "300"]; - private _buttons = ["circle", "triangle", "rectangle", "arrow", "line"]; - private _icons = ["O", "∆", "ロ", "➜", "-"]; + 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 = ["arrowHead", "arrowHead", "dot", "dot", "none"]; + private _arrowEnd = ["none", "arrowEnd", "none", "dot", "none"]; + private _arrowIcons = ["→", "↔︎", "•", "••", " "]; @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 +52,106 @@ export default class InkOptionsMenu extends AntimodeMenu { this._canFade = false; // don't let the inking menu fade away } + getColors = () => { + return this._palette; + } + @action - changeColor = (color: string) => { + changeArrow = (arrowStart: string, arrowEnd: string) => { + SetActiveArrowStart(arrowStart); + SetActiveArrowEnd(arrowEnd); + } + + @action + 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]; + if (this._arrowIcons[i] === " ") { + currIcon = "➤"; + } + } + } + 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() { @@ -49,7 +160,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"> @@ -58,7 +169,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 +179,8 @@ export default class InkOptionsMenu extends AntimodeMenu { return widthPicker; } + + @computed get colorPicker() { var colorPicker = <button className="antimodeMenu-button" @@ -75,7 +188,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"> @@ -84,9 +199,10 @@ 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> + {/* <FontAwesomeIcon icon="pen-nib" size="lg" /> */} + <div className="color-previewII" style={{ backgroundColor: color }}></div> </button>; })} </div>; @@ -94,15 +210,75 @@ export default class InkOptionsMenu extends AntimodeMenu { return colorPicker; } - @computed get shapeButtons() { - return this._buttons.map((btn, i) => <button + @computed get fillPicker() { + var fillPicker = <button className="antimodeMenu-button" - title={`Draw ${btn}`} - key={i} - onPointerDown={action(e => GestureOverlay.Instance.InkShape = btn)} - style={{ backgroundColor: btn === GestureOverlay.Instance.InkShape ? "121212" : "" }}> - {this._icons[i]} - </button>); + key="fill" + title="fillChanger" + onPointerDown={action(e => this._fillBtn = !this._fillBtn)} + style={{ backgroundColor: this._fillBtn ? "121212" : "" }}> + <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"> + {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-previewII" style={{ backgroundColor: color }}></div> + </button>; + })} + + </div>; + } + return fillPicker; + } + + @computed get shapePicker() { + var currIcon; + if (GestureOverlay.Instance.InkShape === "") { + currIcon = <FontAwesomeIcon icon="shapes" size="lg" />; + } 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._shapeBtn ? "121212" : "" }}> + {currIcon} + </button>; + if (this._shapeBtn) { + 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={ttl} + 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() { @@ -112,16 +288,35 @@ 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>; + } + + @computed get dashButton() { + return <button + className="antimodeMenu-button" + title="dash changer" + key="dash" + onPointerDown={e => this.changeDash(e)} + style={{ backgroundColor: ActiveDash() !== "0" ? "121212" : "" }}> + <FontAwesomeIcon icon="ellipsis-h" size="lg" /> + </button>; } render() { const buttons = [ - ...this.shapeButtons, + // <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, this.colorPicker, + this.fillPicker, + this.arrowPicker, + this.dashButton, ]; return this.getElement(buttons); } @@ -134,4 +329,4 @@ Scripting.addGlobal(function activatePen(penBtn: any) { Doc.SetSelectedTool(InkTool.None); InkOptionsMenu.Instance.fadeOut(true); } -});
\ No newline at end of file +}); diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index 1bc7c6fb5..97ed74c10 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -20,8 +20,6 @@ import { CollectionView } from "../CollectionView"; import MarqueeOptionsMenu from "./MarqueeOptionsMenu"; import "./MarqueeView.scss"; import React = require("react"); -import { DateField } from "../../../../fields/DateField"; -import { DocServer } from "../../../DocServer"; interface MarqueeViewProps { getContainerTransform: () => Transform; @@ -260,6 +258,10 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque e.preventDefault(); } } + clearSelection() { + if (window.getSelection) { window.getSelection()?.removeAllRanges(); } + else if (document.getSelection()) { document.getSelection()?.empty(); } + } setPreviewCursor = action((x: number, y: number, drag: boolean) => { if (drag) { @@ -275,6 +277,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque this._downX = x; this._downY = y; PreviewCursor.Show(x, y, this.onKeyPress, this.props.addLiveTextDocument, this.props.getTransform, this.props.addDocument, this.props.nudge); + this.clearSelection(); } }); @@ -349,7 +352,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque backgroundColor: this.props.isAnnotationOverlay ? "#00000015" : isBackground ? "cyan" : undefined, _width: bounds.width, _height: bounds.height, - _LODdisable: true, title: "a nested collection", }); selected.forEach(d => d.context = newCollection); |
