diff options
Diffstat (limited to 'src/client/views/InkingStroke.tsx')
| -rw-r--r-- | src/client/views/InkingStroke.tsx | 57 |
1 files changed, 38 insertions, 19 deletions
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 40fe6aa68..06671961d 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -25,16 +25,16 @@ import { action, IReactionDisposer, observable, reaction } from "mobx"; import { observer } from "mobx-react"; import { Doc, WidthSym } from "../../fields/Doc"; import { InkData, InkField, InkTool } from "../../fields/InkField"; -import { BoolCast, Cast, NumCast, StrCast } from "../../fields/Types"; +import { BoolCast, Cast, NumCast, RTFCast, StrCast } from "../../fields/Types"; import { TraceMobx } from "../../fields/util"; -import { OmitKeys, returnFalse, setupMoveUpEvents } from "../../Utils"; +import { emptyFunction, OmitKeys, returnFalse, setupMoveUpEvents } from "../../Utils"; import { CognitiveServices } from "../cognitive_services/CognitiveServices"; import { InteractionUtils } from "../util/InteractionUtils"; import { SnappingManager } from "../util/SnappingManager"; import { Transform } from "../util/Transform"; import { UndoManager } from "../util/UndoManager"; import { ContextMenu } from "./ContextMenu"; -import { ViewBoxBaseComponent } from "./DocComponent"; +import { DocComponent, ViewBoxBaseComponent } from "./DocComponent"; import { Colors } from "./global/globalEnums"; import { InkControlPtHandles, InkEndPtHandles } from "./InkControlPtHandles"; import "./InkStroke.scss"; @@ -43,6 +43,7 @@ import { InkTangentHandles } from "./InkTangentHandles"; import { FieldView, FieldViewProps } from "./nodes/FieldView"; import { FormattedTextBox } from "./nodes/formattedText/FormattedTextBox"; import Color = require("color"); +import { DocComponentView } from "./nodes/DocumentView"; @observer export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { @@ -67,6 +68,18 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { this._selDisposer?.(); } + // transform is the inherited screentolocal xf plus any scaling that was done to make the stroke + // fit within its panel (e.g., for content fitting views like Lightbox or multicolumn, etc) + screenToLocal = () => this.props.ScreenToLocalTransform().scale(this.props.scaling?.() || 1); + + getAnchor = () => { + console.log(document.activeElement); + return this._subContentView?.getAnchor?.() || this.rootDoc; + } + + scrollFocus = (textAnchor: Doc, smooth: boolean) => { + return this._subContentView?.scrollFocus?.(textAnchor, smooth); + } /** * @returns the center of the ink stroke in the ink document's coordinate space (not screen space, and not the ink data coordinate space); * DocumentDecorations calls getBounds() on DocumentViews which call getCenter() if defined - in the case of ink it needs to be defined since @@ -119,7 +132,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { this._handledClick = false; const inkView = this.props.docViewPath().lastElement(); const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); - const screenPts = inkData.map(point => this.props.ScreenToLocalTransform().inverse().transformPoint( + const screenPts = inkData.map(point => this.screenToLocal().inverse().transformPoint( (point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2)).map(p => ({ X: p[0], Y: p[1] })); const { nearestSeg } = InkStrokeProperties.nearestPtToStroke(screenPts, { X: e.clientX, Y: e.clientY }); @@ -160,7 +173,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { */ ptFromScreen = (scrPt: { X: number, Y: number }) => { const { inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); - const docPt = this.props.ScreenToLocalTransform().transformPoint(scrPt.X, scrPt.Y); + const docPt = this.screenToLocal().transformPoint(scrPt.X, scrPt.Y); const inkPt = { X: (docPt[0] - inkStrokeWidth / 2) / inkScaleX + inkStrokeWidth / 2 + inkLeft, Y: (docPt[1] - inkStrokeWidth / 2) / inkScaleY + inkStrokeWidth / 2 + inkTop, @@ -178,7 +191,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { X: (inkPt.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, Y: (inkPt.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2 }; - const scrPt = this.props.ScreenToLocalTransform().inverse().transformPoint(docPt.X, docPt.Y); + const scrPt = this.screenToLocal().inverse().transformPoint(docPt.X, docPt.Y); return { X: scrPt[0], Y: scrPt[1] }; } @@ -192,7 +205,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { snapPt = (scrPt: { X: number, Y: number }, excludeSegs?: number[]) => { const { inkData } = this.inkScaledData(); const { nearestPt, distance } = InkStrokeProperties.nearestPtToStroke(inkData, this.ptFromScreen(scrPt), excludeSegs ?? []); - return { nearestPt, distance: distance * this.props.ScreenToLocalTransform().inverse().Scale }; + return { nearestPt, distance: distance * this.screenToLocal().inverse().Scale }; } /** @@ -220,10 +233,14 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { }; } + // + // this updates the highlight for the nearest point on the curve to the cursor. + // if the user double clicks, this highlighted point will be added as a control point in the curve. + // @action onPointerMove = (e: React.PointerEvent) => { const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); - const screenPts = inkData.map(point => this.props.ScreenToLocalTransform().inverse().transformPoint( + const screenPts = inkData.map(point => this.screenToLocal().inverse().transformPoint( (point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2)).map(p => ({ X: p[0], Y: p[1] })); const { distance, nearestT, nearestSeg, nearestPt } = InkStrokeProperties.nearestPtToStroke(screenPts, { X: e.clientX, Y: e.clientY }); @@ -246,10 +263,10 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { componentUI = (boundsLeft: number, boundsTop: number) => { const inkDoc = this.props.Document; const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData(); - const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.props.ScreenToLocalTransform().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke + const screenSpaceCenterlineStrokeWidth = Math.min(3, inkStrokeWidth * this.screenToLocal().inverse().Scale); // the width of the blue line widget that shows the centerline of the ink stroke - const screenInkWidth = this.props.ScreenToLocalTransform().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); - const screenPts = inkData.map(point => this.props.ScreenToLocalTransform().inverse().transformPoint( + const screenInkWidth = this.screenToLocal().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth); + const screenPts = inkData.map(point => this.screenToLocal().inverse().transformPoint( (point.X - inkLeft - inkStrokeWidth / 2) * inkScaleX + inkStrokeWidth / 2, (point.Y - inkTop - inkStrokeWidth / 2) * inkScaleY + inkStrokeWidth / 2)).map(p => ({ X: p[0], Y: p[1] })); const screenHdlPts = screenPts; @@ -264,9 +281,10 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { <InkEndPtHandles inkView={this.props.docViewPath().lastElement()} inkDoc={inkDoc} - startPt={this.ptToScreen(inkData[0])} - endPt={this.ptToScreen(inkData.lastElement())} - screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} /></div>) : + startPt={screenPts[0]} + endPt={screenPts.lastElement()} + screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} /> + </div>) : <div className="inkstroke-UI" style={{ clip: `rect(${boundsTop}px, 10000px, 10000px, ${boundsLeft}px)` }}> {InteractionUtils.CreatePolyline(screenPts, 0, 0, Colors.MEDIUM_BLUE, screenInkWidth[0], screenSpaceCenterlineStrokeWidth, StrCast(inkDoc.strokeLineJoin), StrCast(this.layoutDoc.strokeLineCap), StrCast(inkDoc.strokeBezier), @@ -277,17 +295,18 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { inkCtrlPoints={inkData} screenCtrlPoints={screenHdlPts} nearestScreenPt={this.nearestScreenPt} - screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} - ScreenToLocalTransform={this.props.ScreenToLocalTransform} /> + screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} /> <InkTangentHandles inkView={this.props.docViewPath().lastElement()} inkDoc={inkDoc} screenCtrlPoints={screenHdlPts} screenSpaceLineWidth={screenSpaceCenterlineStrokeWidth} - ScreenToLocalTransform={this.props.ScreenToLocalTransform} /> + ScreenToLocalTransform={this.screenToLocal} /> </div>; } + _subContentView: DocComponentView | undefined; + setSubContentView = (doc: DocComponentView) => this._subContentView = doc; render() { TraceMobx(); const { inkData, inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY, inkWidth, inkHeight } = this.inkScaledData(); @@ -315,7 +334,6 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { StrCast(this.layoutDoc.strokeBezier), !closed ? "none" : fillColor === "transparent" ? "none" : fillColor, startMarker, endMarker, markerScale, undefined, inkScaleX, inkScaleY, "", this.props.pointerEvents ?? (this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted"), 0.0, false, downHdlr); - return <div className="inkStroke-wrapper"> <svg className="inkStroke" style={{ @@ -336,7 +354,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { {clickableLine(this.onPointerDown)} {inkLine} </svg> - {!closed ? (null) : + {!closed || (!RTFCast(this.rootDoc.text)?.Text && !this.props.isSelected()) ? (null) : <div className="inkStroke-text" style={{ color: StrCast(this.layoutDoc.textColor, "black"), pointerEvents: this.props.isDocumentActive?.() ? "all" : undefined, @@ -344,6 +362,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { }}> <FormattedTextBox {...OmitKeys(this.props, ['children']).omit} + setContentView={this.setSubContentView} // this makes the inkingStroke the "dominant" component - ie, it will show the inking UI when selected (not text) yPadding={10} xPadding={10} fieldKey={"text"} |
