From b88f3a79b4558b222864b7c925fd0d5086cdcea2 Mon Sep 17 00:00:00 2001 From: eleanor-park Date: Thu, 11 Jul 2024 12:08:26 -0400 Subject: Revert "Merge branch 'eleanor-gptdraw' into master" This reverts commit 4438e7fe202ff4091b26f073122e7866ec9abb46, reversing changes made to 59ca918ea0918b41f1e2fa4b6acb8725ca9b44af. --- src/client/views/GestureOverlay.tsx | 28 +- src/client/views/LightboxView.scss | 24 +- src/client/views/LightboxView.tsx | 7 - src/client/views/MainView.tsx | 5 - src/client/views/MarqueeAnnotator.tsx | 146 -------- src/client/views/collections/CollectionMenu.scss | 2 +- .../collectionFreeForm/CollectionFreeFormView.tsx | 242 ++++-------- .../collectionFreeForm/ImageLabelHandler.scss | 14 - .../collections/collectionFreeForm/MarqueeView.tsx | 6 +- src/client/views/global/globalScripts.ts | 4 +- src/client/views/nodes/PDFBox.scss | 16 +- src/client/views/nodes/PDFBox.tsx | 37 +- src/client/views/pdf/AnchorMenu.tsx | 14 - src/client/views/pdf/PDFViewer.tsx | 3 - src/client/views/smartdraw/DrawingPalette.scss | 11 - src/client/views/smartdraw/DrawingPalette.tsx | 89 ----- src/client/views/smartdraw/SmartDrawHandler.tsx | 409 --------------------- 17 files changed, 107 insertions(+), 950 deletions(-) delete mode 100644 src/client/views/smartdraw/DrawingPalette.scss delete mode 100644 src/client/views/smartdraw/DrawingPalette.tsx delete mode 100644 src/client/views/smartdraw/SmartDrawHandler.tsx (limited to 'src/client/views') diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx index a1f7712c1..e3e252593 100644 --- a/src/client/views/GestureOverlay.tsx +++ b/src/client/views/GestureOverlay.tsx @@ -240,15 +240,15 @@ export class GestureOverlay extends ObservableReactComponent { @observable private _doc: Opt = undefined; @observable private _docTarget: Opt = undefined; @observable private _docView: Opt = undefined; - @observable private _showPalette: boolean = false; @computed get leftBorder() { return Math.min(this._props.PanelWidth / 4, this._props.maxBorder[0]); } // prettier-ignore @computed get topBorder() { return Math.min(this._props.PanelHeight / 4, this._props.maxBorder[1]); } // prettier-ignore @@ -204,9 +202,6 @@ export class LightboxView extends ObservableReactComponent { toggleFitWidth = () => { this._doc && (this._doc._layout_fitWidth = !this._doc._layout_fitWidth); }; - togglePalette = () => { - this._showPalette = !this._showPalette; - }; togglePen = () => { Doc.ActiveTool = Doc.ActiveTool === InkTool.Pen ? InkTool.None : InkTool.Pen; }; @@ -324,10 +319,8 @@ export class LightboxView extends ObservableReactComponent { {toggleBtn('lightboxView-navBtn', 'toggle reading view', this._doc?._layout_fitWidth, 'book-open', 'book', this.toggleFitWidth)} {toggleBtn('lightboxView-tabBtn', 'open document in a tab', false, 'file-download', '', this.downloadDoc)} - {toggleBtn('lightboxView-paletteBtn', 'toggle annotation palette', this._showPalette === true, 'palette', '', this.togglePalette)} {toggleBtn('lightboxView-penBtn', 'toggle pen annotation', Doc.ActiveTool === InkTool.Pen, 'pen', '', this.togglePen)} {toggleBtn('lightboxView-exploreBtn', 'toggle navigate only mode', SnappingManager.ExploreMode, 'globe-americas', '', this.toggleExplore)} - {this._showPalette && } ); } diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 30720a3a2..ef1bcfb64 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -76,7 +76,6 @@ import { PresBox } from './nodes/trails'; import { AnchorMenu } from './pdf/AnchorMenu'; import { GPTPopup } from './pdf/GPTPopup/GPTPopup'; import { TopBar } from './topbar/TopBar'; -import { SmartDrawHandler } from './smartdraw/SmartDrawHandler'; const { LEFT_MENU_WIDTH, TOPBAR_HEIGHT } = require('./global/globalCssVariables.module.scss'); // prettier-ignore const _global = (window /* browser */ || global) /* node */ as any; @@ -318,7 +317,6 @@ export class MainView extends ObservableReactComponent<{}> { fa.faCompass, fa.faSnowflake, fa.faStar, - fa.faSplotch, fa.faMicrophone, fa.faCircleHalfStroke, fa.faKeyboard, @@ -396,7 +394,6 @@ export class MainView extends ObservableReactComponent<{}> { fa.faArrowsLeftRight, fa.faPause, fa.faPen, - fa.faUserPen, fa.faPenNib, fa.faPhone, fa.faPlay, @@ -442,7 +439,6 @@ export class MainView extends ObservableReactComponent<{}> { fa.faEyeDropper, fa.faPaintRoller, fa.faBars, - fa.faBarsStaggered, fa.faBrush, fa.faShapes, fa.faEllipsisH, @@ -1093,7 +1089,6 @@ export class MainView extends ObservableReactComponent<{}> { - diff --git a/src/client/views/MarqueeAnnotator.tsx b/src/client/views/MarqueeAnnotator.tsx index f06f3efe0..c18ac6738 100644 --- a/src/client/views/MarqueeAnnotator.tsx +++ b/src/client/views/MarqueeAnnotator.tsx @@ -28,7 +28,6 @@ export interface MarqueeAnnotatorProps { marqueeContainer: HTMLDivElement; docView: () => DocumentView; savedAnnotations: () => ObservableMap; - savedTapes: () => ObservableMap; selectionText: () => string; annotationLayer: HTMLDivElement; addDocument: (doc: Doc) => boolean; @@ -75,7 +74,6 @@ export class MarqueeAnnotator extends ObservableReactComponent): Opt => { - // const savedTapeMap = savedTapes?.values() && Array.from(savedTapes?.values()).length ? savedTapes : this.props.savedTapes(); - // if (savedTapeMap.size === 0) return undefined; - // const tapes = Array.from(savedTapeMap.values())[0]; - // const doc = this.props.Document; - // const scale = (this.props.annotationLayerScaling?.() || 1) * NumCast(doc._freeform_scale, 1); - // if (tapes.length && (tapes[0] as any).marqueeing) { - // const anno = tapes[0]; - // const containerOffset = this.props.containerOffset?.() || [0, 0]; - // const tape = Docs.Create.FreeformDocument([], { - // onClick: isLinkButton ? FollowLinkScript() : undefined, - // backgroundColor: color, - // annotationOn: this.props.Document, - // title: 'Tape on ' + this.props.Document.title, - // }); - // tape.x = NumCast(doc.freeform_panX_min) + (parseInt(anno.style.left || '0') - containerOffset[0]) / scale; - // tape.y = NumCast(doc.freeform_panY_min) + (parseInt(anno.style.top || '0') - containerOffset[1]) / scale; - // tape._height = parseInt(anno.style.height || '0') / scale; - // tape._width = parseInt(anno.style.width || '0') / scale; - // anno.remove(); - // savedTapeMap.clear(); - // return tape; - // } - - // const textRegionAnno = Docs.Create.ConfigDocument({ - // annotationOn: this.props.Document, - // text: this.props.selectionText() as any, // text want an RTFfield, but strings are acceptable, too. - // text_html: this.props.selectionText() as any, - // backgroundColor: 'transparent', - // presentation_duration: 2100, - // presentation_transition: 500, - // presentation_zoomText: true, - // title: '>' + this.props.Document.title, - // }); - // const textRegionAnnoProto = textRegionAnno[DocData]; - // let minX = Number.MAX_VALUE; - // let maxX = -Number.MAX_VALUE; - // let minY = Number.MAX_VALUE; - // let maxY = -Number.MIN_VALUE; - // const annoRects: string[] = []; - // savedAnnoMap.forEach((value: HTMLDivElement[]) => - // value.forEach(anno => { - // const x = parseInt(anno.style.left ?? '0'); - // const y = parseInt(anno.style.top ?? '0'); - // const height = parseInt(anno.style.height ?? '0'); - // const width = parseInt(anno.style.width ?? '0'); - // annoRects.push(`${x}:${y}:${width}:${height}`); - // anno.remove(); - // minY = Math.min(NumCast(y), minY); - // minX = Math.min(NumCast(x), minX); - // maxY = Math.max(NumCast(y) + NumCast(height), maxY); - // maxX = Math.max(NumCast(x) + NumCast(width), maxX); - // }) - // ); - - // textRegionAnnoProto.y = Math.max(minY, 0); - // textRegionAnnoProto.x = Math.max(minX, 0); - // textRegionAnnoProto.height = Math.max(maxY, 0) - Math.max(minY, 0); - // textRegionAnnoProto.width = Math.max(maxX, 0) - Math.max(minX, 0); - // textRegionAnnoProto.backgroundColor = color; - // // mainAnnoDocProto.text = this._selectionText; - // textRegionAnnoProto.text_inlineAnnotations = new List(annoRects); - // textRegionAnnoProto.opacity = 0; - // textRegionAnnoProto.layout_unrendered = true; - // savedAnnoMap.clear(); - // return textRegionAnno; - // }; - - @undoBatch - makeTapeDocument = (color: string, isLinkButton?: boolean, savedTapes?: ObservableMap): Opt => { - // const savedAnnoMap = savedTapes?.values() && Array.from(savedTapes?.values()).length ? savedTapes : this.props.savedTapes(); - // if (savedAnnoMap.size === 0) return undefined; - // const savedAnnos = Array.from(savedAnnoMap.values())[0]; - const doc = this.props.Document; - const scale = (this.props.annotationLayerScaling?.() || 1) * NumCast(doc._freeform_scale, 1); - const marqueeAnno = Docs.Create.FreeformDocument([], { - onClick: isLinkButton ? FollowLinkScript() : undefined, - backgroundColor: color, - annotationOn: this.props.Document, - title: 'Annotation on ' + this.props.Document.title, - }); - marqueeAnno.x = NumCast(doc.freeform_panX_min) / scale; - marqueeAnno.y = NumCast(doc.freeform_panY_min) / scale; - marqueeAnno._height = parseInt('100') / scale; - marqueeAnno._width = parseInt('100') / scale; - return marqueeAnno; - // } - - // const textRegionAnno = Docs.Create.ConfigDocument({ - // annotationOn: this.props.Document, - // text: this.props.selectionText() as any, // text want an RTFfield, but strings are acceptable, too. - // text_html: this.props.selectionText() as any, - // backgroundColor: 'transparent', - // presentation_duration: 2100, - // presentation_transition: 500, - // presentation_zoomText: true, - // title: '>' + this.props.Document.title, - // }); - // const textRegionAnnoProto = textRegionAnno[DocData]; - // let minX = Number.MAX_VALUE; - // let maxX = -Number.MAX_VALUE; - // let minY = Number.MAX_VALUE; - // let maxY = -Number.MIN_VALUE; - // const annoRects: string[] = []; - // savedAnnoMap.forEach((value: HTMLDivElement[]) => - // value.forEach(anno => { - // const x = parseInt(anno.style.left ?? '0'); - // const y = parseInt(anno.style.top ?? '0'); - // const height = parseInt(anno.style.height ?? '0'); - // const width = parseInt(anno.style.width ?? '0'); - // annoRects.push(`${x}:${y}:${width}:${height}`); - // anno.remove(); - // minY = Math.min(NumCast(y), minY); - // minX = Math.min(NumCast(x), minX); - // maxY = Math.max(NumCast(y) + NumCast(height), maxY); - // maxX = Math.max(NumCast(x) + NumCast(width), maxX); - // }) - // ); - - // textRegionAnnoProto.y = Math.max(minY, 0); - // textRegionAnnoProto.x = Math.max(minX, 0); - // textRegionAnnoProto.height = Math.max(maxY, 0) - Math.max(minY, 0); - // textRegionAnnoProto.width = Math.max(maxX, 0) - Math.max(minX, 0); - // textRegionAnnoProto.backgroundColor = color; - // // mainAnnoDocProto.text = this._selectionText; - // textRegionAnnoProto.text_inlineAnnotations = new List(annoRects); - // textRegionAnnoProto.opacity = 0; - // textRegionAnnoProto.layout_unrendered = true; - // savedAnnoMap.clear(); - // return textRegionAnno; - }; - @action highlight = (color: string, isLinkButton: boolean, savedAnnotations?: ObservableMap, addAsAnnotation?: boolean) => { // creates annotation documents for current highlights @@ -272,15 +136,6 @@ export class MarqueeAnnotator extends ObservableReactComponent, addAsAnnotation?: boolean) => { - // creates annotation documents for current highlights - const effectiveAcl = GetEffectiveAcl(this.props.Document[DocData]); - const tape = [AclAugment, AclSelfEdit, AclEdit, AclAdmin].includes(effectiveAcl) && this.makeTapeDocument(color, isLinkButton, savedTapes); - addAsAnnotation && tape && this.props.addDocument(tape); - return tape as Doc; - }; - public static previewNewAnnotation = action((savedAnnotations: ObservableMap, annotationLayer: HTMLDivElement, div: HTMLDivElement, page: number) => { div.style.backgroundColor = '#ACCEF7'; div.style.opacity = '0.5'; @@ -327,7 +182,6 @@ export class MarqueeAnnotator extends ObservableReactComponent this.props.anchorMenuClick?.()?.(this.highlight(this.props.highlightDragSrcColor ?? 'rgba(173, 216, 230, 0.75)', true, undefined, true)), 'make sidebar annotation'); AnchorMenu.Instance.OnAudio = unimplementedFunction; AnchorMenu.Instance.Highlight = (color: string) => this.highlight(color, false, undefined, true); - AnchorMenu.Instance.Tape = (color: string) => this.tape(color, false, undefined, true); AnchorMenu.Instance.GetAnchor = (savedAnnotations?: ObservableMap /* , addAsAnnotation?: boolean */) => this.highlight('rgba(173, 216, 230, 0.75)', true, savedAnnotations, true); AnchorMenu.Instance.onMakeAnchor = () => AnchorMenu.Instance.GetAnchor(undefined, true); diff --git a/src/client/views/collections/CollectionMenu.scss b/src/client/views/collections/CollectionMenu.scss index 45d9394ed..3ec875df4 100644 --- a/src/client/views/collections/CollectionMenu.scss +++ b/src/client/views/collections/CollectionMenu.scss @@ -6,7 +6,7 @@ align-content: center; justify-content: space-between; background-color: $dark-gray; - height: 40px; + height: 35px; border-bottom: $standard-border; padding: 0 10px; align-items: center; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 8f8cb9083..d611db1f8 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1,7 +1,7 @@ /* eslint-disable react/jsx-props-no-spreading */ /* eslint-disable jsx-a11y/click-events-have-key-events */ /* eslint-disable jsx-a11y/no-static-element-interactions */ -import { Bezier, Point } from 'bezier-js'; +import { Bezier } from 'bezier-js'; import { Colors } from 'browndash-components'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; @@ -27,7 +27,6 @@ import { aggregateBounds, clamp, emptyFunction, intersectRect, Utils } from '../ import { Docs } from '../../../documents/Documents'; import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes'; import { DocUtils } from '../../../documents/DocUtils'; -import { FitCurve, GenerateControlPoints } from '../../../util/bezierFit'; import { DragManager } from '../../../util/DragManager'; import { dropActionType } from '../../../util/DropActionTypes'; import { CompileScript } from '../../../util/Scripting'; @@ -56,7 +55,6 @@ import { CollectionFreeFormPannableContents } from './CollectionFreeFormPannable import { CollectionFreeFormRemoteCursors } from './CollectionFreeFormRemoteCursors'; import './CollectionFreeFormView.scss'; import { MarqueeView } from './MarqueeView'; -import { DrawingOptions, SmartDrawHandler } from '../../smartdraw/SmartDrawHandler'; @observer class CollectionFreeFormOverlayView extends React.Component<{ elements: () => ViewDefResult[] }> { @@ -120,7 +118,6 @@ export class CollectionFreeFormView extends CollectionSubView(); @observable _marqueeViewRef = React.createRef(); @@ -500,30 +497,28 @@ export class CollectionFreeFormView extends CollectionSubView { this._deleteList.lastElement()?._props.removeDocument?.(this._deleteList.map(ink => ink.Document)); @@ -615,48 +609,34 @@ export class CollectionFreeFormView extends CollectionSubView { - e.stopImmediatePropagation(); + /** + * Erases strokes by intersecting them with an invisible "eraser stroke". + * By default this iterates through all intersected ink strokes, determines their segmentation, draws back the non-intersected segments, + * and deletes the original stroke. + */ + @action + onEraserMove = (e: PointerEvent, down: number[], delta: number[]) => { const currPoint = { X: e.clientX, Y: e.clientY }; this._eraserPts.push([currPoint.X, currPoint.Y]); this._eraserPts = this._eraserPts.slice(Math.max(0, this._eraserPts.length - 5)); - if (Doc.ActiveTool === InkTool.RadiusEraser) { - const strokeMap: Map = this.getRadiusEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint); - strokeMap.forEach((intersects, stroke) => { - if (!this._deleteList.includes(stroke)) { - this._deleteList.push(stroke); - SetActiveInkWidth(StrCast(stroke.Document.stroke_width?.toString()) || '1'); - SetActiveInkColor(StrCast(stroke.Document.color?.toString()) || 'black'); - const segments = this.radiusErase(stroke, intersects.sort()); - segments?.forEach(segment => - this.forceStrokeGesture( - e, - Gestures.Stroke, - segment.reduce((data, curve) => [...data, ...curve.points.map(p => stroke.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[]) - ) - ); - } - stroke.layoutDoc.opacity = 0; - stroke.layoutDoc.dontIntersect = true; - }); - } else { - this.getEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint).forEach(intersect => { - if (!this._deleteList.includes(intersect.inkView)) { - this._deleteList.push(intersect.inkView); - SetActiveInkWidth(StrCast(intersect.inkView.Document.stroke_width?.toString()) || '1'); - SetActiveInkColor(StrCast(intersect.inkView.Document.color?.toString()) || 'black'); - // create a new curve by appending all curves of the current segment together in order to render a single new stroke. - if (Doc.ActiveTool !== InkTool.StrokeEraser) { - // this._eraserLock++; - const segments = this.segmentErase(intersect.inkView, intersect.t); // intersect.t is where the eraser intersected the ink stroke - want to remove the segment that starts at the intersection just before this t value and goes to the one just after it - const newStrokes = segments?.map(segment => { - const points = segment.reduce((data, curve) => [...data, ...curve.points.map(p => intersect.inkView.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[]); - const bounds = InkField.getBounds(points); - const B = this.screenToFreeformContentsXf.transformBounds(bounds.left, bounds.top, bounds.width, bounds.height); - const inkWidth = ActiveInkWidth() * this.ScreenToLocalBoxXf().Scale; - return Docs.Create.InkDocument( - points, - { title: 'stroke', + // if (this._eraserLock) return false; // leaving this commented out in case the idea is revisited in the future + this.getEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint).forEach(intersect => { + if (!this._deleteList.includes(intersect.inkView)) { + this._deleteList.push(intersect.inkView); + SetActiveInkWidth(StrCast(intersect.inkView.Document.stroke_width?.toString()) || '1'); + SetActiveInkColor(StrCast(intersect.inkView.Document.color?.toString()) || 'black'); + // create a new curve by appending all curves of the current segment together in order to render a single new stroke. + if (Doc.ActiveTool !== InkTool.StrokeEraser) { + // this._eraserLock++; + const segments = this.segmentErase(intersect.inkView, intersect.t); // intersect.t is where the eraser intersected the ink stroke - want to remove the segment that starts at the intersection just before this t value and goes to the one just after it + const newStrokes = segments?.map(segment => { + const points = segment.reduce((data, curve) => [...data, ...curve.points.map(p => intersect.inkView.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[]); + const bounds = InkField.getBounds(points); + const B = this.screenToFreeformContentsXf.transformBounds(bounds.left, bounds.top, bounds.width, bounds.height); + const inkWidth = ActiveInkWidth() * this.ScreenToLocalBoxXf().Scale; + return Docs.Create.InkDocument( + points, + { title: 'stroke', x: B.x - inkWidth / 2, y: B.y - inkWidth / 2, _width: B.width + inkWidth, @@ -675,30 +655,14 @@ export class CollectionFreeFormView extends CollectionSubView this._eraserLock--); } - }); - } - return false; - }; - - /** - * Erases strokes by intersecting them with an invisible "eraser stroke". - * By default this iterates through all intersected ink strokes, determines their segmentation, draws back the non-intersected segments, - * and deletes the original stroke. - */ - @action - onEraserMove = (e: PointerEvent, down: number[], delta: number[]) => { - this.erase(e, delta); - // if (this._eraserLock) return false; // leaving this commented out in case the idea is revisited in the future + // Lower ink opacity to give the user a visual indicator of deletion. + intersect.inkView.layoutDoc.opacity = 0; + intersect.inkView.layoutDoc.dontIntersect = true; + } + }); return false; }; - @action - onEraserClick = (e: PointerEvent, doubleTap?: boolean) => { - e.preventDefault(); - e.stopImmediatePropagation(); - this.erase(e, [0, 0]); - }; - /** * Erases strokes by intersecting them with a circle of variable radius. Essentially creates an InkField for the * eraser circle, then determines its intersections with other ink strokes. Each stroke's DocumentView and its @@ -708,32 +672,32 @@ export class CollectionFreeFormView extends CollectionSubView { - // const currPoint = { X: e.clientX, Y: e.clientY }; - // this._eraserPts.push([currPoint.X, currPoint.Y]); - // this._eraserPts = this._eraserPts.slice(Math.max(0, this._eraserPts.length - 5)); - // const strokeMap: Map = this.getRadiusEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint); - - // strokeMap.forEach((intersects, stroke) => { - // if (!this._deleteList.includes(stroke)) { - // this._deleteList.push(stroke); - // SetActiveInkWidth(StrCast(stroke.Document.stroke_width?.toString()) || '1'); - // SetActiveInkColor(StrCast(stroke.Document.color?.toString()) || 'black'); - // const segments = this.radiusErase(stroke, intersects.sort()); - // segments?.forEach(segment => - // this.forceStrokeGesture( - // e, - // Gestures.Stroke, - // segment.reduce((data, curve) => [...data, ...curve.points.map(p => stroke.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[]) - // ) - // ); - // } - // stroke.layoutDoc.opacity = 0; - // stroke.layoutDoc.dontIntersect = true; - // }); - // return false; - // }; + @action + onRadiusEraserMove = (e: PointerEvent, down: number[], delta: number[]) => { + const currPoint = { X: e.clientX, Y: e.clientY }; + this._eraserPts.push([currPoint.X, currPoint.Y]); + this._eraserPts = this._eraserPts.slice(Math.max(0, this._eraserPts.length - 5)); + const strokeMap: Map = this.getRadiusEraserIntersections({ X: currPoint.X - delta[0], Y: currPoint.Y - delta[1] }, currPoint); + + strokeMap.forEach((intersects, stroke) => { + if (!this._deleteList.includes(stroke)) { + this._deleteList.push(stroke); + SetActiveInkWidth(StrCast(stroke.Document.stroke_width?.toString()) || '1'); + SetActiveInkColor(StrCast(stroke.Document.color?.toString()) || 'black'); + const segments = this.radiusErase(stroke, intersects.sort()); + segments?.forEach(segment => + this.forceStrokeGesture( + e, + Gestures.Stroke, + segment.reduce((data, curve) => [...data, ...curve.points.map(p => stroke.ComponentView?.ptToScreen?.({ X: p.x, Y: p.y }) ?? { X: 0, Y: 0 })], [] as PointData[]) + ) + ); + } + stroke.layoutDoc.opacity = 0; + stroke.layoutDoc.dontIntersect = true; + }); + return false; + }; forceStrokeGesture = (e: PointerEvent, gesture: Gestures, points: InkData, text?: any) => { this.onGesture(e, new GestureUtils.GestureEvent(gesture, points, InkField.getBounds(points), text)); @@ -764,7 +728,7 @@ export class CollectionFreeFormView extends CollectionSubView { - SmartDrawHandler.Instance.displaySmartDrawHandler(e.pageX, e.pageY, this.createDrawing, this.removeDrawing); - }; - - _drawing: Doc[] = []; - @undoBatch - createDrawing = (e: React.PointerEvent, strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => { - strokeData.forEach((stroke: [InkData, string, string]) => { - const bounds = InkField.getBounds(stroke[0]); - const B = this.screenToFreeformContentsXf.transformBounds(bounds.left, bounds.top, bounds.width, bounds.height); - const inkWidth = ActiveInkWidth() * this.ScreenToLocalBoxXf().Scale; - const inkDoc = Docs.Create.InkDocument( - stroke[0], - { title: 'stroke', - x: B.x - inkWidth / 2, - y: B.y - inkWidth / 2, - _width: B.width + inkWidth, - _height: B.height + inkWidth, - stroke_showLabel: BoolCast(Doc.UserDoc().activeInkHideTextLabels)}, // prettier-ignore - inkWidth, - stroke[1], - undefined, - stroke[2] === 'none' ? undefined : stroke[2] - ); - this._drawing.push(inkDoc); - this.addDocument(inkDoc); - }); - const collection = this._marqueeViewRef.current?.collection(undefined, true, this._drawing); - if (collection) { - const docData = collection[DocData]; - docData.title = opts.text; - docData.drawingInput = opts.text; - docData.drawingComplexity = opts.complexity; - docData.drawingColored = opts.autoColor; - docData.drawingSize = opts.size; - docData.drawingData = gptRes; - } - this._batch?.end(); - }; - - removeDrawing = (doc?: Doc) => { - this._batch = UndoManager.StartBatch('regenerateDrawing'); - if (doc) { - const docData: Doc = doc[DocData]; - const children = docData.data as unknown as Doc[]; - this._props.removeDocument?.(doc); - this._props.removeDocument?.(children); - } else { - this._props.removeDocument?.(this._drawing); - } - this._drawing = []; - }; - @action zoom = (pointX: number, pointY: number, deltaY: number): void => { if (this.Document.isGroup || this.Document[(this._props.viewField ?? '_') + 'freeform_noZoom']) return; @@ -1921,10 +1831,8 @@ export class CollectionFreeFormView extends CollectionSubView { - const locPt = this.ScreenToLocalBoxXf().transformPoint(e.clientX, e.clientY); - this._eraserX = locPt[0]; - this._eraserY = locPt[1]; - // Doc.ActiveTool === InkTool.RadiusEraser ? this._childPointerEvents = 'none' : this._childPointerEvents = 'all' + this._eraserX = e.clientX; + this._eraserY = e.clientY; // super.setCursorPosition(this.getTransform().transformPoint(e.clientX, e.clientY)); }; @@ -2031,14 +1939,6 @@ export class CollectionFreeFormView extends CollectionSubView { - this._showDrawingEditor = !this._showDrawingEditor; - this._showDrawingEditor ? SmartDrawHandler.Instance.displayRegenerate(this._downX, this._downY - 10, this.createDrawing, this.removeDrawing) : SmartDrawHandler.Instance.hideRegenerate(); - }), - icon: 'pen-to-square', - }); this._props.renderDepth && optionItems.push({ description: 'Use Background Color as Default', @@ -2243,8 +2143,8 @@ export class CollectionFreeFormView extends CollectionSubView Transform; @@ -375,8 +374,8 @@ export class MarqueeView extends ObservableReactComponent { SetActiveInkColor(StrCast(value)); selected?.type === DocumentType.INK && setActiveTool(GestureOverlay.Instance.InkShape ?? InkTool.Pen, true, false);}, }], [ 'eraserWidth', { - checkResult: () => ActiveEraserWidth() === 0 ? 1 : ActiveEraserWidth(), + checkResult: () => ActiveEraserWidth(), setInk: (doc: Doc) => { }, - setMode: () => { SetEraserWidth(value);}, + setMode: () => { SetEraserWidth(value.toString());}, }] ]); diff --git a/src/client/views/nodes/PDFBox.scss b/src/client/views/nodes/PDFBox.scss index 6e24b2931..7bca1230f 100644 --- a/src/client/views/nodes/PDFBox.scss +++ b/src/client/views/nodes/PDFBox.scss @@ -20,27 +20,15 @@ top: 0; left: 0; - .pdfBox-sidebarBtn-container { - display: flex; - flex-direction: row; - position: absolute; - width: 53px; - height: 33px; - right: 5px; - align-items: center; - justify-content: space-between; - z-index: 1; - } - // glr: This should really be the same component as text and PDFs .pdfBox-sidebarBtn { background: $black; height: 25px; width: 25px; - // right: 5px; + right: 5px; color: $white; display: flex; - // position: absolute; + position: absolute; align-items: center; justify-content: center; border-radius: 3px; diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx index 782df99f6..8db68ddfe 100644 --- a/src/client/views/nodes/PDFBox.tsx +++ b/src/client/views/nodes/PDFBox.tsx @@ -1,8 +1,6 @@ /* eslint-disable jsx-a11y/no-static-element-interactions */ /* eslint-disable jsx-a11y/control-has-associated-label */ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { IconButton } from 'browndash-components'; -import { black } from 'colors'; import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx'; import { observer } from 'mobx-react'; import * as Pdfjs from 'pdfjs-dist'; @@ -505,30 +503,17 @@ export class PDFBox extends ViewBoxAnnotatableComponent() { } @computed get sidebarHandle() { return ( -
-
- {/* // onPointerDown={e => this.sidebarBtnDown(e, true)} */} - } onPointerDown={e => this.sidebarBtnDown(e, true)} /> -
-
- } onPointerDown={e => this.sidebarBtnDown(e, true)} /> -
+
this.sidebarBtnDown(e, true)}> +
); } diff --git a/src/client/views/pdf/AnchorMenu.tsx b/src/client/views/pdf/AnchorMenu.tsx index df990b0c0..2f6824466 100644 --- a/src/client/views/pdf/AnchorMenu.tsx +++ b/src/client/views/pdf/AnchorMenu.tsx @@ -51,7 +51,6 @@ export class AnchorMenu extends AntimodeMenu { public StartDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction; public StartCropDrag: (e: PointerEvent, ele: HTMLElement) => void = unimplementedFunction; public Highlight: (color: string) => Opt = (/* color: string */) => undefined; - public Tape: (color: string) => Opt = (/* color: string */) => undefined; public GetAnchor: (savedAnnotations: Opt>, addAsAnnotation: boolean) => Opt = emptyFunction; public Delete: () => void = unimplementedFunction; public PinToPres: () => void = unimplementedFunction; @@ -173,12 +172,6 @@ export class AnchorMenu extends AntimodeMenu { AnchorMenu.Instance.fadeOut(true); }; - @action - tapeClicked = () => { - this.Tape(this.highlightColor); - // AnchorMenu.Instance.fadeOut(true); - }; - @computed get highlighter() { return ( @@ -189,13 +182,6 @@ export class AnchorMenu extends AntimodeMenu { colorPicker={this.highlightColor} color={SettingsManager.userColor} /> - } - onClick={this.tapeClicked} - colorPicker={this.highlightColor} - color={SettingsManager.userColor} - /> ); diff --git a/src/client/views/pdf/PDFViewer.tsx b/src/client/views/pdf/PDFViewer.tsx index fbe3518ec..db47a84e1 100644 --- a/src/client/views/pdf/PDFViewer.tsx +++ b/src/client/views/pdf/PDFViewer.tsx @@ -65,7 +65,6 @@ export class PDFViewer extends ObservableReactComponent { @observable _pageSizes: { width: number; height: number }[] = []; @observable _savedAnnotations = new ObservableMap(); - @observable _savedTapes = new ObservableMap(); @observable _textSelecting = true; @observable _showWaiting = true; @observable Index: number = -1; @@ -582,7 +581,6 @@ export class PDFViewer extends ObservableReactComponent { return
; } savedAnnotations = () => this._savedAnnotations; - savedTapes = () => this._savedTapes; addDocumentWrapper = (doc: Doc | Doc[]) => this._props.addDocument!(doc); render() { TraceMobx(); @@ -616,7 +614,6 @@ export class PDFViewer extends ObservableReactComponent { docView={this._props.pdfBox.DocumentView!} finishMarquee={this.finishMarquee} savedAnnotations={this.savedAnnotations} - savedTapes={this.savedTapes} selectionText={this.selectionText} annotationLayer={this._annotationLayer.current} marqueeContainer={this._mainCont.current} diff --git a/src/client/views/smartdraw/DrawingPalette.scss b/src/client/views/smartdraw/DrawingPalette.scss deleted file mode 100644 index 0f1152b71..000000000 --- a/src/client/views/smartdraw/DrawingPalette.scss +++ /dev/null @@ -1,11 +0,0 @@ -.drawing-palette { - display: grid; - grid-template-columns: auto; - position: absolute; - right: 14px; - width: 170px; - height: 170px; - top: 50px; - border-radius: 5px; - background-color: white; -} diff --git a/src/client/views/smartdraw/DrawingPalette.tsx b/src/client/views/smartdraw/DrawingPalette.tsx deleted file mode 100644 index 87a39bc85..000000000 --- a/src/client/views/smartdraw/DrawingPalette.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import { computed, makeObservable, observable } from 'mobx'; -import { observer } from 'mobx-react'; -import * as React from 'react'; -import { returnAll, returnFalse, returnOne, returnZero } from '../../../ClientUtils'; -import { Doc, StrListCast } from '../../../fields/Doc'; -import { emptyFunction } from '../../../Utils'; -import { CollectionViewType } from '../../documents/DocumentTypes'; -import { MarqueeView } from '../collections/collectionFreeForm'; -import { CollectionGridView } from '../collections/collectionGrid'; -import { CollectionStackingView } from '../collections/CollectionStackingView'; -import { DocumentView } from '../nodes/DocumentView'; -import { FieldViewProps } from '../nodes/FieldView'; -import { ObservableReactComponent } from '../ObservableReactComponent'; -import './DrawingPalette.scss'; - -@observer -export class DrawingPalette extends ObservableReactComponent<{}> { - @observable private _savedDrawings: Doc[] = []; - @observable _marqueeViewRef = React.createRef(); - private _stackRef = React.createRef(); - - constructor(props: any) { - super(props); - makeObservable(this); - } - - panelWidth = () => 100; - panelHeight = () => 100; - - getCollection = () => { - return this._marqueeViewRef.current?.collection(undefined, false, this._savedDrawings) || new Doc(); - }; - - @computed get savedDrawingAnnos() { - // const savedAnnos = Doc.MyDrawingAnnos; - return ( -
- {/* */} - {/* */} -
- ); - } - - render() { - return ( -
- {/* {this._savedDrawings.map(doc => { - return ; - })} */} - {/* */} - {} - {/* */} - {this.savedDrawingAnnos} -
- ); - } -} diff --git a/src/client/views/smartdraw/SmartDrawHandler.tsx b/src/client/views/smartdraw/SmartDrawHandler.tsx deleted file mode 100644 index d24cc9d50..000000000 --- a/src/client/views/smartdraw/SmartDrawHandler.tsx +++ /dev/null @@ -1,409 +0,0 @@ -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { action, makeObservable, observable } from 'mobx'; -import { observer } from 'mobx-react'; -import React from 'react'; -import { SettingsManager } from '../../util/SettingsManager'; -import { ObservableReactComponent } from '../ObservableReactComponent'; -import { Button, IconButton } from 'browndash-components'; -import ReactLoading from 'react-loading'; -import { AiOutlineSend } from 'react-icons/ai'; -// import './ImageLabelHandler.scss'; -import { gptAPICall, GPTCallType } from '../../apis/gpt/GPT'; -import { InkData } from '../../../fields/InkField'; -import { SVGToBezier } from '../../util/bezierFit'; -const { parse } = require('svgson'); -import { Slider, Switch } from '@mui/material'; -import { Doc } from '../../../fields/Doc'; -import { DocData } from '../../../fields/DocSymbols'; -import { DocumentView } from '../nodes/DocumentView'; - -export interface DrawingOptions { - text: string; - complexity: number; - size: number; - autoColor: boolean; - x: number; - y: number; -} - -@observer -export class SmartDrawHandler extends ObservableReactComponent<{}> { - static Instance: SmartDrawHandler; - - @observable private _display: boolean = false; - @observable private _pageX: number = 0; - @observable private _pageY: number = 0; - @observable private _yRelativeToTop: boolean = true; - @observable private _isLoading: boolean = false; - @observable private _userInput: string = ''; - @observable private _showOptions: boolean = false; - @observable private _showEditBox: boolean = false; - @observable private _showRegenerate: boolean = false; - @observable private _complexity: number = 5; - @observable private _size: number = 200; - @observable private _autoColor: boolean = true; - @observable private _regenInput: string = ''; - private _addFunc: (e: React.PointerEvent, strokeList: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void = () => {}; - private _deleteFunc: (doc?: Doc) => void = () => {}; - private _lastInput: DrawingOptions = { text: '', complexity: 5, size: 300, autoColor: true, x: 0, y: 0 }; - private _lastResponse: string = ''; - private _selectedDoc: Doc | undefined = undefined; - - constructor(props: any) { - super(props); - makeObservable(this); - SmartDrawHandler.Instance = this; - } - - @action - setUserInput = (input: string) => { - this._userInput = input; - }; - - @action - setRegenInput = (input: string) => { - this._regenInput = input; - }; - - @action - setShowOptions = () => { - this._showOptions = !this._showOptions; - }; - - @action - setComplexity = (val: number) => { - this._complexity = val; - }; - - @action - setSize = (val: number) => { - this._size = val; - }; - - @action - setAutoColor = () => { - this._autoColor = !this._autoColor; - }; - - @action - displaySmartDrawHandler = (x: number, y: number, addFunc: (e: React.PointerEvent, strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void, deleteFunc: (doc?: Doc) => void) => { - this._pageX = x; - this._pageY = y; - this._display = true; - this._addFunc = addFunc; - this._deleteFunc = deleteFunc; - }; - - @action - displayRegenerate = (x: number, y: number, addFunc: (e: React.PointerEvent, strokeData: [InkData, string, string][], opts: DrawingOptions, gptRes: string, containerDoc?: Doc) => void, deleteFunc: (doc?: Doc) => void) => { - this._selectedDoc = DocumentView.SelectedDocs().lastElement(); - const docData = this._selectedDoc[DocData]; - this._addFunc = addFunc; - this._deleteFunc = deleteFunc; - this._pageX = x; - this._pageY = y; - this._showRegenerate = true; - this._lastResponse = docData.drawingData as string; - this._lastInput = { text: docData.drawingInput as string, complexity: docData.drawingComplexity as number, size: docData.drawingSize as number, autoColor: docData.drawingColored as boolean, x: this._pageX, y: this._pageY }; - }; - - @action - hideSmartDrawHandler = () => { - this._showRegenerate = false; - this._display = false; - this._isLoading = false; - this._showOptions = false; - this._userInput = ''; - this._complexity = 5; - this._size = 300; - this._autoColor = true; - // this._regenInput = '' - }; - - @action - hideRegenerate = () => { - this._showRegenerate = false; - this._isLoading = false; - this._regenInput = ''; - }; - - _errorOccurredOnce = false; - @action - drawWithGPT = async (e: React.PointerEvent, input: string) => { - if (input === '') return; - this._lastInput = { text: input, complexity: this._complexity, size: this._size, autoColor: this._autoColor, x: e.clientX, y: e.clientY }; - this._isLoading = true; - this._showOptions = false; - try { - const res = await gptAPICall(`"${input}", "${this._complexity}", "${this._size}"`, GPTCallType.DRAW, undefined, true); - if (!res) { - console.error('GPT call failed'); - return; - } - console.log(res); - await this.parseResponse(e, res, { X: e.clientX, Y: e.clientY }, false); - this.hideSmartDrawHandler(); - this._showRegenerate = true; - this._errorOccurredOnce = false; - } catch (err) { - if (this._errorOccurredOnce) { - console.error('GPT call failed', err); - this._errorOccurredOnce = false; - } else { - this._errorOccurredOnce = true; - this.drawWithGPT(e, input); - } - } - this._isLoading = false; - }; - - @action - edit = () => { - this._showEditBox = !this._showEditBox; - }; - - @action - regenerate = async (e: React.PointerEvent) => { - this._isLoading = true; - try { - let res; - if (this._regenInput !== '') { - const prompt: string = `This is your previously generated svg code: ${this._lastResponse} for the user input "${this._lastInput.text}". Please regenerate it with the provided specifications.`; - res = await gptAPICall(`"${this._regenInput}"`, GPTCallType.DRAW, prompt, true); - this._lastInput.text = `${this._lastInput.text} + ${this._regenInput}`; - } else { - res = await gptAPICall(`"${this._lastInput.text}", "${this._lastInput.complexity}", "${this._lastInput.size}"`, GPTCallType.DRAW, undefined, true); - } - if (!res) { - console.error('GPT call failed'); - return; - } - console.log(res); - this.parseResponse(e, res, { X: this._lastInput.x, Y: this._lastInput.y }, true); - } catch (err) { - console.error('GPT call failed', err); - } - this._isLoading = false; - this._regenInput = ''; - this._showEditBox = false; - }; - - @action - parseResponse = async (e: React.PointerEvent, res: string, startPoint: { X: number; Y: number }, regenerate: boolean) => { - const svg = res.match(/]*>([\s\S]*?)<\/svg>/g); - console.log('start point is', startPoint); - if (svg) { - this._lastResponse = svg[0]; - const svgObject = await parse(svg[0]); - const svgStrokes: any = svgObject.children; - const strokeData: [InkData, string, string][] = []; - console.log('autocolor is', this._autoColor); - svgStrokes.forEach((child: any) => { - const convertedBezier: InkData = SVGToBezier(child.name, child.attributes); - strokeData.push([ - convertedBezier.map(point => { - return { X: point.X + startPoint.X - this._size / 1.5, Y: point.Y + startPoint.Y - this._size / 2 }; - }), - (regenerate ? this._lastInput.autoColor : this._autoColor) ? child.attributes.stroke : undefined, - (regenerate ? this._lastInput.autoColor : this._autoColor) ? child.attributes.fill : undefined, - ]); - }); - if (regenerate) { - this._deleteFunc(this._selectedDoc); - this._addFunc(e, strokeData, this._lastInput, svg[0], this._selectedDoc); - } else { - this._addFunc(e, strokeData, this._lastInput, svg[0]); - } - } - }; - - render() { - if (this._display) { - return ( -
-
- { - this.hideSmartDrawHandler(); - this.hideRegenerate(); - }} - icon={} - color={SettingsManager.userColor} - style={{ width: '19px' }} - /> - { - this.setUserInput(e.target.value); - }} - placeholder="Enter item to draw" - /> -
- {this._showOptions && ( - <> -
-
- Auto color - -
-
- Complexity - { - this.setComplexity(val as number); - }} - valueLabelDisplay="auto" - /> -
-
- Size (in pixels) - { - this.setSize(val as number); - }} - valueLabelDisplay="auto" - /> -
-
- - )} -
- ); - } else if (this._showRegenerate) { - return ( -
-
- : } - color={SettingsManager.userColor} - onClick={e => { - this.regenerate(e as React.PointerEvent); - }} - /> - } color={SettingsManager.userColor} onClick={this.edit} /> - {this._showEditBox && ( -
- { - this.setRegenInput(e.target.value); - }} - placeholder="Edit instructions" - /> -
- )} -
-
- ); - } else { - return <>; - } - } -} -- cgit v1.2.3-70-g09d2