aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/collectionFreeForm
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/views/collections/collectionFreeForm')
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx70
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx104
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx84
3 files changed, 113 insertions, 145 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
index f5a5492e3..5f890c810 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLinkView.tsx
@@ -3,7 +3,7 @@ import { observer } from "mobx-react";
import { Doc, Field } from "../../../../fields/Doc";
import { Id } from "../../../../fields/FieldSymbols";
import { List } from "../../../../fields/List";
-import { NumCast } from "../../../../fields/Types";
+import { Cast, NumCast } from "../../../../fields/Types";
import { emptyFunction, setupMoveUpEvents, Utils } from '../../../../Utils';
import { LinkManager } from "../../../util/LinkManager";
import { SelectionManager } from "../../../util/SelectionManager";
@@ -30,7 +30,14 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
componentWillUnmount() { this._anchorDisposer?.(); }
@action timeout = action(() => (Date.now() < this._start++ + 1000) && (this._timeout = setTimeout(this.timeout, 25)));
componentDidMount() {
- this._anchorDisposer = reaction(() => [this.props.A.props.ScreenToLocalTransform(), this.props.B.props.ScreenToLocalTransform()],
+ this._anchorDisposer = reaction(() => [
+ this.props.A.props.ScreenToLocalTransform(),
+ Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor1, Doc, null)?.annotationOn, Doc, null)?.scrollTop,
+ Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor1, Doc, null)?.annotationOn, Doc, null)?._highlights,
+ this.props.B.props.ScreenToLocalTransform(),
+ Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor2, Doc, null)?.annotationOn, Doc, null)?.scrollTop,
+ Cast(Cast(Cast(this.props.A.rootDoc, Doc, null)?.anchor2, Doc, null)?.annotationOn, Doc, null)?._highlights,
+ ],
action(() => {
this._start = Date.now();
this._timeout && clearTimeout(this._timeout);
@@ -45,14 +52,10 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
if (SnappingManager.GetIsDragging() || !A.ContentDiv || !B.ContentDiv) return;
setTimeout(action(() => this._opacity = 0.75), 0); // since the render code depends on querying the Dom through getBoudndingClientRect, we need to delay triggering render()
setTimeout(action(() => (!LinkDocs.length || !linkDoc.linkDisplay) && (this._opacity = 0.05)), 750); // this will unhighlight the link line.
- const acont = A.ContentDiv.getElementsByClassName("linkAnchorBox-cont");
- const bcont = B.ContentDiv.getElementsByClassName("linkAnchorBox-cont");
- const adiv = acont.length ? acont[0] : A.ContentDiv;
- const bdiv = bcont.length ? bcont[0] : B.ContentDiv;
- const a = adiv.getBoundingClientRect();
- const b = bdiv.getBoundingClientRect();
- const { left: aleft, top: atop, width: awidth, height: aheight } = adiv.parentElement!.getBoundingClientRect();
- const { left: bleft, top: btop, width: bwidth, height: bheight } = bdiv.parentElement!.getBoundingClientRect();
+ const a = A.ContentDiv.getBoundingClientRect();
+ const b = B.ContentDiv.getBoundingClientRect();
+ const { left: aleft, top: atop, width: awidth, height: aheight } = A.ContentDiv.parentElement!.getBoundingClientRect();
+ const { left: bleft, top: btop, width: bwidth, height: bheight } = B.ContentDiv.parentElement!.getBoundingClientRect();
const apt = Utils.closestPtBetweenRectangles(aleft, atop, awidth, aheight, bleft, btop, bwidth, bheight, a.left + a.width / 2, a.top + a.height / 2);
const bpt = Utils.closestPtBetweenRectangles(bleft, btop, bwidth, bheight, aleft, atop, awidth, aheight, apt.point.x, apt.point.y);
@@ -75,6 +78,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const mpy = mp[1] / A.props.PanelHeight();
if (mpx >= 0 && mpx <= 1) linkDoc.anchor1_x = mpx * 100;
if (mpy >= 0 && mpy <= 1) linkDoc.anchor1_y = mpy * 100;
+ if (getComputedStyle(targetAhyperlink).fontSize === "0px") linkDoc.opacity = 0;
+ else linkDoc.opacity = 1;
}
if (!targetBhyperlink) {
if (linkDoc.linkAutoMove) {
@@ -88,6 +93,8 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
const mpy = mp[1] / B.props.PanelHeight();
if (mpx >= 0 && mpx <= 1) linkDoc.anchor2_x = mpx * 100;
if (mpy >= 0 && mpy <= 1) linkDoc.anchor2_y = mpy * 100;
+ if (getComputedStyle(targetBhyperlink).fontSize === "0px") linkDoc.opacity = 0;
+ else linkDoc.opacity = 1;
}
}
@@ -154,25 +161,6 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
this.toggleProperties();
}
- // componentToHex = (c: number) => {
- // let hex = c.toString(16);
- // return hex.length == 1 ? "0" + hex : hex;
- // }
-
- // rgbToHex = (rgbString: string) => {
- // if (rgbString != "black") {
- // const splitString = rgbString.split(/rgb|\(|\)|,| /)
- // let values: number[] = []
- // splitString.forEach(elt => {
- // if (elt) {
- // values.push(parseInt(elt))
- // }
- // })
- // return "#" + this.componentToHex(values[0]) + this.componentToHex(values[1]) + this.componentToHex(values[2]);
- // }
- // return "#000000"
- // }
-
@computed.struct get renderData() {
this._start; SnappingManager.GetIsDragging();
const { A, B, LinkDocs } = this.props;
@@ -190,32 +178,18 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
if (!a.width || !b.width) return undefined;
const aDocBounds = (A.props as any).DocumentView?.().getBounds() || { left: 0, right: 0, top: 0, bottom: 0 };
const bDocBounds = (B.props as any).DocumentView?.().getBounds() || { left: 0, right: 0, top: 0, bottom: 0 };
- const acentX = (a.left + a.right) / 2;
- const acentY = (a.top + a.bottom) / 2;
- const bcentX = (b.left + b.right) / 2;
- const bcentY = (b.top + b.bottom) / 2;
- const pt1Arc = ((acentX - aDocBounds.left) > 0.1 && (aDocBounds.right - acentX) > 0.1) ||
- ((acentY - aDocBounds.top) > 0.1 && (aDocBounds.bottom - acentY) > 0.1);
- const pt2Arc = ((bcentX - bDocBounds.left) > 0.1 && (bDocBounds.right - bcentX) > 0.1) ||
- ((bcentY - bDocBounds.top) > 0.1 && (bDocBounds.bottom - bcentY) > 0.1);
- const atop2 = this.visibleY(adiv);
- const btop2 = this.visibleY(bdiv);
const aleft = this.visibleX(adiv);
const bleft = this.visibleX(bdiv);
const clipped = aleft !== a.left || atop !== a.top || bleft !== b.left || btop !== b.top;
const pt1 = [aleft + a.width / 2, atop + a.height / 2];
const pt2 = [bleft + b.width / 2, btop + b.width / 2];
- const pt1vec = [pt1[0] - (aDocBounds.left + aDocBounds.right) / 2, pt1[1] - (aDocBounds.top + aDocBounds.bottom) / 2];
- const pt2vec = [pt2[0] - (bDocBounds.left + bDocBounds.right) / 2, pt2[1] - (bDocBounds.top + bDocBounds.bottom) / 2];
+ const pt1vec = [(bDocBounds.left + bDocBounds.right) / 2 - pt1[0], (bDocBounds.top + bDocBounds.bottom) / 2 - pt1[1]];
+ const pt2vec = [(aDocBounds.left + aDocBounds.right) / 2 - pt2[0], (aDocBounds.top + aDocBounds.bottom) / 2 - pt2[1]];
const pt1len = Math.sqrt((pt1vec[0] * pt1vec[0]) + (pt1vec[1] * pt1vec[1]));
const pt2len = Math.sqrt((pt2vec[0] * pt2vec[0]) + (pt2vec[1] * pt2vec[1]));
const ptlen = Math.sqrt((pt1[0] - pt2[0]) * (pt1[0] - pt2[0]) + (pt1[1] - pt2[1]) * (pt1[1] - pt2[1])) / 2;
- const pt1norm = clipped ? [0, 0] : !pt1Arc ? [pt1vec[0] / pt1len * ptlen, pt1vec[1] / pt1len * ptlen] :
- Math.abs(acentY - aDocBounds.top) < 0.01 ||
- Math.abs(acentY - aDocBounds.bottom) < 0.01 ? [0, (pt2[1] - pt1[1]) / 2] : [(pt2[0] - pt1[0]) / 2, 0];
- const pt2norm = clipped ? [0, 0] : !pt2Arc ? [pt2vec[0] / pt2len * ptlen, pt2vec[1] / pt2len * ptlen] :
- Math.abs(bcentY - bDocBounds.top) < 0.01 ||
- Math.abs(bcentY - bDocBounds.bottom) < 0.01 ? [0, (pt1[1] - pt2[1]) / 2] : [(pt1[0] - pt2[0]) / 2, 0];
+ const pt1norm = clipped ? [0, 0] : [pt1vec[0] / pt1len * ptlen, pt1vec[1] / pt1len * ptlen];
+ const pt2norm = clipped ? [0, 0] : [pt2vec[0] / pt2len * ptlen, pt2vec[1] / pt2len * ptlen];
const pt1normlen = Math.sqrt(pt1norm[0] * pt1norm[0] + pt1norm[1] * pt1norm[1]) || 1;
const pt2normlen = Math.sqrt(pt2norm[0] * pt2norm[0] + pt2norm[1] * pt2norm[1]) || 1;
const pt1normalized = [pt1norm[0] / pt1normlen, pt1norm[1] / pt1normlen];
@@ -253,7 +227,7 @@ export class CollectionFreeFormLinkView extends React.Component<CollectionFreeFo
this.props.LinkDocs[0].displayArrow = false;
}
- return !a.width || !b.width || ((!this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<>
+ return this.props.LinkDocs[0].opacity === 0 || !a.width || !b.width || ((!this.props.LinkDocs[0].linkDisplay) && !aActive && !bActive) ? (null) : (<>
<defs>
<marker id="arrowhead" markerWidth="4" markerHeight="3"
refX="0" refY="1.5" orient="auto">
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index f70dd7840..f4d2d55d5 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -3,13 +3,13 @@ import { action, computed, IReactionDisposer, observable, reaction, runInAction
import { observer } from "mobx-react";
import { computedFn } from "mobx-utils";
import { DateField } from "../../../../fields/DateField";
-import { Doc, DocListCast, HeightSym, Opt, StrListCast, WidthSym } from "../../../../fields/Doc";
+import { DataSym, Doc, DocListCast, HeightSym, Opt, StrListCast, WidthSym } from "../../../../fields/Doc";
import { Id } from "../../../../fields/FieldSymbols";
import { InkData, InkField, InkTool, PointData, Segment } from "../../../../fields/InkField";
import { List } from "../../../../fields/List";
import { ObjectField } from "../../../../fields/ObjectField";
import { RichTextField } from "../../../../fields/RichTextField";
-import { createSchema, listSpec } from "../../../../fields/Schema";
+import { listSpec } from "../../../../fields/Schema";
import { ScriptField } from "../../../../fields/ScriptField";
import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types";
import { ImageField } from "../../../../fields/URLField";
@@ -18,7 +18,7 @@ import { GestureUtils } from "../../../../pen-gestures/GestureUtils";
import { aggregateBounds, emptyFunction, intersectRect, returnFalse, setupMoveUpEvents, Utils } from "../../../../Utils";
import { CognitiveServices } from "../../../cognitive_services/CognitiveServices";
import { DocServer } from "../../../DocServer";
-import { Docs, DocumentOptions, DocUtils } from "../../../documents/Documents";
+import { Docs, DocUtils } from "../../../documents/Documents";
import { DocumentType } from "../../../documents/DocumentTypes";
import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
import { DocumentManager } from "../../../util/DocumentManager";
@@ -26,6 +26,7 @@ import { DragManager, dropActionType } from "../../../util/DragManager";
import { HistoryUtil } from "../../../util/History";
import { InteractionUtils } from "../../../util/InteractionUtils";
import { LinkManager } from "../../../util/LinkManager";
+import { RecordingApi } from "../../../util/RecordingApi";
import { ScriptingGlobals } from "../../../util/ScriptingGlobals";
import { SearchUtil } from "../../../util/SearchUtil";
import { SelectionManager } from "../../../util/SelectionManager";
@@ -41,6 +42,7 @@ import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveIn
import { LightboxView } from "../../LightboxView";
import { CollectionFreeFormDocumentView } from "../../nodes/CollectionFreeFormDocumentView";
import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment, ViewSpecPrefix } from "../../nodes/DocumentView";
+import { FieldViewProps } from "../../nodes/FieldView";
import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
import { PresBox } from "../../nodes/trails/PresBox";
import { VideoBox } from "../../nodes/VideoBox";
@@ -50,29 +52,14 @@ import { CollectionDockingView } from "../CollectionDockingView";
import { CollectionSubView } from "../CollectionSubView";
import { TreeViewType } from "../CollectionTreeView";
import { CollectionViewType } from "../CollectionView";
+import { TabDocView } from "../TabDocView";
import { computePivotLayout, computerPassLayout, computerStarburstLayout, computeTimelineLayout, PoolData, ViewDefBounds, ViewDefResult } from "./CollectionFreeFormLayoutEngines";
import { CollectionFreeFormRemoteCursors } from "./CollectionFreeFormRemoteCursors";
import "./CollectionFreeFormView.scss";
import { MarqueeView } from "./MarqueeView";
import React = require("react");
-import { FieldView, FieldViewProps } from "../../nodes/FieldView";
-import { InkTranscription } from "../../InkTranscription";
import e = require("connect-flash");
-import { RecordingApi } from "../../../util/RecordingApi";
-export const panZoomSchema = createSchema({
- _panX: "number",
- _panY: "number",
- _currentTimecode: "number",
- _timecodeToShow: "number",
- _currentFrame: "number",
- _useClusters: "boolean",
- _viewTransition: "string",
- _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
- _fitToBox: "boolean",
- scrollHeight: "number" // this will be set when the collection is an annotation overlay for a PDF/Webpage
-});
export type collectionFreeformViewProps = {
annotationLayerHostsContent?: boolean; // whether to force scaling of content (needed by ImageBox)
@@ -140,16 +127,20 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this.props.PanelWidth() / (this.contentBounds.r - this.contentBounds.x))
};
}
- @computed get fitToContent() { return (this.props.fitContentsToDoc?.() || this.Document._fitToBox) && !this.isAnnotationOverlay; }
- @computed get contentBounds() { return aggregateBounds(this._layoutElements.filter(e => e.bounds && !e.bounds.z).map(e => e.bounds!), NumCast(this.layoutDoc._xPadding, 10), NumCast(this.layoutDoc._yPadding, 10)); }
- @computed get nativeWidth() { return this.fitToContent ? 0 : Doc.NativeWidth(this.Document); }
- @computed get nativeHeight() { return this.fitToContent ? 0 : Doc.NativeHeight(this.Document); }
+ @computed get fitContentsToBox() { return (this.props.fitContentsToBox?.() || this.Document._fitContentsToBox) && !this.isAnnotationOverlay; }
+ @computed get contentBounds() {
+ const cb = Cast(this.rootDoc.contentBounds, listSpec("number"));
+ return cb ? {x:cb[0], y:cb[1], r:cb[2], b: cb[3]} :
+ this.props.contentBounds?.() ?? aggregateBounds(this._layoutElements.filter(e => e.bounds && !e.bounds.z).map(e => e.bounds!), NumCast(this.layoutDoc._xPadding, 10), NumCast(this.layoutDoc._yPadding, 10));
+ }
+ @computed get nativeWidth() { return this.fitContentsToBox ? 0 : Doc.NativeWidth(this.Document); }
+ @computed get nativeHeight() { return this.fitContentsToBox ? 0 : Doc.NativeHeight(this.Document); }
@computed get cachedCenteringShiftX(): number {
- const scaling = this.fitToContent || !this.contentScaling ? 1 : this.contentScaling;
+ const scaling = this.fitContentsToBox || !this.contentScaling ? 1 : this.contentScaling;
return this.props.isAnnotationOverlay ? 0 : this.props.PanelWidth() / 2 / scaling; // shift so pan position is at center of window for non-overlay collections
}
@computed get cachedCenteringShiftY(): number {
- const scaling = this.fitToContent || !this.contentScaling ? 1 : this.contentScaling;
+ const scaling = this.fitContentsToBox || !this.contentScaling ? 1 : this.contentScaling;
return this.props.isAnnotationOverlay ? 0 : this.props.PanelHeight() / 2 / scaling;// shift so pan position is at center of window for non-overlay collections
}
@computed get cachedGetLocalTransform(): Transform {
@@ -174,8 +165,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this.layoutDoc._panY = vals.bounds.cy;
this.layoutDoc._viewScale = vals.scale;
}
- freeformData = (force?: boolean) => !this._firstRender && (this.fitToContent || force) ? this.fitToContentVals : undefined;
- reverseNativeScaling = () => this.fitToContent ? true : false;
+ freeformData = (force?: boolean) => !this._firstRender && (this.fitContentsToBox || force) ? this.fitToContentVals : undefined;
+ reverseNativeScaling = () => this.fitContentsToBox ? true : false;
panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document._panX);
panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document._panY);
zoomScaling = () => (this.freeformData()?.scale ?? NumCast(this.Document[this.scaleFieldKey], 1));
@@ -716,7 +707,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
onPointerMove = (e: PointerEvent): void => {
- console.log("this is onPointerMove");
if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE)) return;
if (InteractionUtils.IsType(e, InteractionUtils.TOUCHTYPE)) {
Doc.UserDoc().activeInkTool = InkTool.None;
@@ -839,7 +829,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
handle1PointerMove = (e: TouchEvent, me: InteractionUtils.MultiTouchEvent<TouchEvent>) => {
- console.log("getting here yeet");
if (!e.cancelBubble) {
const myTouches = InteractionUtils.GetMyTargetTouches(me, this.prevPoints, true);
if (myTouches[0]) {
@@ -1122,7 +1111,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this.props.focus(doc, options);
} else {
const xfToCollection = options?.docTransform ?? Transform.Identity();
- const savedState = { panX: NumCast(this.Document._panX), panY: NumCast(this.Document._panY), scale: this.Document[this.scaleFieldKey] };
+ const savedState = { panX: NumCast(this.Document._panX), panY: NumCast(this.Document._panY), scale: options?.willZoom ? this.Document[this.scaleFieldKey] : undefined };
const newState = HistoryUtil.getState();
const cantTransform = /*this.props.isAnnotationOverlay ||*/ ((this.rootDoc._isGroup || this.layoutDoc._lockedTransform) && !LightboxView.LightboxDoc);
const { panX, panY, scale } = cantTransform ? savedState : this.calculatePanIntoView(doc, xfToCollection, options?.willZoom ? options?.scale || .75 : undefined);
@@ -1211,7 +1200,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
@action
onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
const docView = fieldProps.DocumentView?.();
- if (docView && (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey || docView.rootDoc._singleLine) && ["Tab", "Enter"].includes(e.key)) {
+ if (docView && (e.metaKey || e.ctrlKey || e.altKey || docView.rootDoc._singleLine) && ["Tab", "Enter"].includes(e.key)) {
e.stopPropagation?.();
const below = !e.altKey && e.key !== "Tab";
const layoutKey = StrCast(docView.LayoutFieldKey);
@@ -1243,7 +1232,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
Document={childLayout}
renderDepth={this.props.renderDepth + 1}
replica={entry.replica}
- dataTransition={entry.transition}
suppressSetHeight={this.layoutEngine ? true : false}
renderCutoffProvider={this.renderCutoffProvider}
ContainingCollectionView={this.props.CollectionView}
@@ -1283,7 +1271,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
dontRegisterView={this.props.dontRenderDocuments || this.props.dontRegisterView}
pointerEvents={this.pointerEvents}
jitterRotation={this.props.styleProvider?.(childLayout, this.props, StyleProp.JitterRotation) || 0}
- //fitToBox={this.props.fitToBox || BoolCast(this.props.freezeChildDimensions)} // bcz: check this
+ //fitContentsToBox={this.props.fitContentsToBox || BoolCast(this.props.freezeChildDimensions)} // bcz: check this
/>;
}
addDocTab = action((doc: Doc, where: string) => {
@@ -1505,7 +1493,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}));
}
- replaceCanvases = (oldDiv: HTMLElement, newDiv: HTMLElement) => {
+ static replaceCanvases(oldDiv: HTMLElement, newDiv: HTMLElement) {
if (oldDiv.childNodes && newDiv) {
for (let i = 0; i < oldDiv.childNodes.length; i++) {
this.replaceCanvases(oldDiv.childNodes[i] as HTMLElement, newDiv.childNodes[i] as HTMLElement);
@@ -1524,32 +1512,39 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
}
}
- updateIcon = () => {
- const docViewContent = this.props.docViewPath().lastElement().ContentDiv!;
+ updateIcon = () => CollectionFreeFormView.UpdateIcon(
+ this.layoutDoc[Id] + "-icon" + (new Date()).getTime(),
+ this.props.docViewPath().lastElement().ContentDiv!,
+ this.layoutDoc[WidthSym](), this.layoutDoc[HeightSym](),
+ this.props.PanelWidth(), this.props.PanelHeight(), 0,
+ (iconFile, nativeWidth, nativeHeight) => {
+ this.dataDoc.icon = new ImageField(iconFile);
+ this.dataDoc["icon-nativeWidth"] = nativeWidth;
+ this.dataDoc["icon-nativeHeight"] = nativeHeight;
+ });
+
+ public static UpdateIcon(filename:string, docViewContent:HTMLElement, width: number, height: number,
+ panelWidth:number, panelHeight: number, scrollTop:number, cb:(iconFile:string, nativeWidth:number, nativeHeight:number) => any) {
const newDiv = docViewContent.cloneNode(true) as HTMLDivElement;
- newDiv.style.width = (this.layoutDoc[WidthSym]()).toString();
- newDiv.style.height = (this.layoutDoc[HeightSym]()).toString();
+ newDiv.style.width = width.toString();
+ newDiv.style.height = height.toString();
this.replaceCanvases(docViewContent, newDiv);
- const htmlString = this._mainCont && new XMLSerializer().serializeToString(newDiv);
- const nativeWidth = this.layoutDoc[WidthSym]();
- const nativeHeight = this.layoutDoc[HeightSym]();
-
+ const htmlString = new XMLSerializer().serializeToString(newDiv);
+ const nativeWidth = width;
+ const nativeHeight = height;
CreateImage(
- "",
+ Utils.prepend(""),
document.styleSheets,
htmlString,
nativeWidth,
- nativeWidth * this.props.PanelHeight() / this.props.PanelWidth(),
- NumCast(this.layoutDoc._scrollTop)
+ nativeWidth * panelHeight / panelWidth,
+ scrollTop
).then
((data_url: any) => {
- VideoBox.convertDataUri(data_url, this.layoutDoc[Id] + "-icon" + (new Date()).getTime(), true, this.layoutDoc[Id] + "-icon").then(
- returnedfilename => setTimeout(action(() => {
-
- this.dataDoc.icon = new ImageField(returnedfilename);
- this.dataDoc["icon-nativeWidth"] = nativeWidth;
- this.dataDoc["icon-nativeHeight"] = nativeHeight;
- }), 500));
+ VideoBox.convertDataUri(data_url, filename).then(
+ returnedfilename => setTimeout(() => {
+ cb(returnedfilename as string, nativeWidth, nativeHeight);
+ }, 500));
})
.catch(function (error: any) {
console.error('oops, something went wrong!', error);
@@ -1620,8 +1615,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
const appearanceItems = appearance && "subitems" in appearance ? appearance.subitems : [];
appearanceItems.push({ description: "Reset View", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: "compress-arrows-alt" });
!Doc.UserDoc().noviceMode && Doc.UserDoc().defaultTextLayout && appearanceItems.push({ description: "Reset default note style", event: () => Doc.UserDoc().defaultTextLayout = undefined, icon: "eye" });
- appearanceItems.push({ description: `${this.fitToContent ? "Make Zoomable" : "Scale to Window"}`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" });
- appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: "compress-arrows-alt" });
+ appearanceItems.push({ description: `${this.fitContentsToBox ? "Make Zoomable" : "Scale to Window"}`, event: () => this.Document._fitContentsToBox = !this.fitContentsToBox, icon: !this.fitContentsToBox ? "expand-arrows-alt" : "compress-arrows-alt" });
+ appearanceItems.push({ description: `Pin View`, event: () => TabDocView.PinDoc(this.rootDoc, {pinDocView:true, panelWidth: this.props.PanelWidth(), panelHeight:this.props.PanelHeight()}), icon: "map-pin" });
+ //appearanceItems.push({ description: `update icon`, event: this.updateIcon, icon: "compress-arrows-alt" });
this.props.ContainingCollectionView &&
appearanceItems.push({ description: "Ungroup collection", event: this.promoteCollection, icon: "table" });
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 40851a88a..051da795f 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -1,6 +1,6 @@
import { action, computed, observable } from "mobx";
import { observer } from "mobx-react";
-import { AclAdmin, AclAugment, AclEdit, DataSym, Doc, Opt } from "../../../../fields/Doc";
+import { AclAdmin, AclAugment, AclEdit, DataSym, Doc, DocListCastAsync, Opt } from "../../../../fields/Doc";
import { Id } from "../../../../fields/FieldSymbols";
import { InkData, InkField, InkTool } from "../../../../fields/InkField";
import { List } from "../../../../fields/List";
@@ -14,13 +14,12 @@ import { CognitiveServices } from "../../../cognitive_services/CognitiveServices
import { Docs, DocumentOptions, DocUtils } from "../../../documents/Documents";
import { DocumentType } from "../../../documents/DocumentTypes";
import { CurrentUserUtils } from "../../../util/CurrentUserUtils";
-import { DocumentManager } from "../../../util/DocumentManager";
import { SelectionManager } from "../../../util/SelectionManager";
import { Transform } from "../../../util/Transform";
import { undoBatch, UndoManager } from "../../../util/UndoManager";
import { ContextMenu } from "../../ContextMenu";
import { FormattedTextBox } from "../../nodes/formattedText/FormattedTextBox";
-import { PresBox } from "../../nodes/trails/PresBox";
+import { PinViewProps, PresBox } from "../../nodes/trails/PresBox";
import { PresMovement } from "../../nodes/trails/PresEnums";
import { VideoBox } from "../../nodes/VideoBox";
import { pasteImageBitmap } from "../../nodes/WebBoxRenderer";
@@ -31,6 +30,7 @@ import { TreeView } from "../TreeView";
import { MarqueeOptionsMenu } from "./MarqueeOptionsMenu";
import "./MarqueeView.scss";
import React = require("react");
+import { TabDocView } from "../TabDocView";
interface MarqueeViewProps {
getContainerTransform: () => Transform;
@@ -44,6 +44,14 @@ interface MarqueeViewProps {
ungroup?: () => void;
setPreviewCursor?: (func: (x: number, y: number, drag: boolean, hide: boolean) => void) => void;
}
+
+export interface MarqueeViewBounds {
+ left: number;
+ top: number;
+ width: number;
+ height: number;
+}
+
@observer
export class MarqueeView extends React.Component<SubCollectionViewProps & MarqueeViewProps>
{
@@ -52,7 +60,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
@observable _lastY: number = 0;
@observable _downX: number = 0;
@observable _downY: number = 0;
- @observable _visible: boolean = false;
+ @observable _visible: boolean = false; // selection rentangle for marquee selection/free hand lasso is visible
@observable _lassoPts: [number, number][] = [];
@observable _lassoFreehand: boolean = false;
@@ -62,7 +70,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
const topLeft = this.Transform.transformPoint(this._downX < this._lastX ? this._downX : this._lastX, this._downY < this._lastY ? this._downY : this._lastY);
// nda - args to transformDirection is just x and y diff btw downX/Y and lastX/Y
const size = this.Transform.transformDirection(this._lastX - this._downX, this._lastY - this._downY);
- return { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) };
+ const bounds:MarqueeViewBounds = { left: topLeft[0], top: topLeft[1], width: Math.abs(size[0]), height: Math.abs(size[1]) }
+ return bounds;
}
get inkDoc() { return this.props.Document; }
get ink() { return Cast(this.props.Document.ink, InkField); }
@@ -209,8 +218,8 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this._downY = this._lastY = e.clientY;
if (!(e.nativeEvent as any).marqueeHit) {
(e.nativeEvent as any).marqueeHit = true;
- // allow marquee if right click OR alt+left click
- if (e.button === 2 || (e.button === 0 && e.altKey)) {
+ // allow marquee if right click OR alt+left click OR in adding presentation slide & left key drag mode
+ if (e.button === 2 || (e.button === 0 && e.altKey) || (PresBox.startMarquee && e.button === 0)) {
// if (e.altKey || (MarqueeView.DragMarquee && this.props.active(true))) {
this.setPreviewCursor(e.clientX, e.clientY, true, false);
// (!e.altKey) && e.stopPropagation(); // bcz: removed so that you can alt-click on button in a collection to switch link following behaviors.
@@ -241,6 +250,9 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.cleanupInteractions(true); // stop listening for events if another lower-level handle (e.g. another Marquee) has stopPropagated this
}
e.altKey && e.preventDefault();
+ if (PresBox.startMarquee) {
+ e.stopPropagation();
+ }
}
@action
@@ -261,11 +273,14 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
document.removeEventListener("pointerdown", hideMarquee);
document.removeEventListener("wheel", hideMarquee);
};
- if (!this._commandExecuted && (Math.abs(this.Bounds.height * this.Bounds.width) > 100)) {
+ if (PresBox.startMarquee) {
+ this.pinWithView();
+ PresBox.startMarquee = false;
+ }
+ if (!this._commandExecuted && (Math.abs(this.Bounds.height * this.Bounds.width) > 100) && !PresBox.startMarquee) {
MarqueeOptionsMenu.Instance.createCollection = this.collection;
MarqueeOptionsMenu.Instance.delete = this.delete;
MarqueeOptionsMenu.Instance.summarize = this.summary;
- // MarqueeOptionsMenu.Instance.inkToText = this.syntaxHighlight;
MarqueeOptionsMenu.Instance.showMarquee = this.showMarquee;
MarqueeOptionsMenu.Instance.hideMarquee = this.hideMarquee;
MarqueeOptionsMenu.Instance.jumpTo(e.clientX, e.clientY);
@@ -380,40 +395,23 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
this.hideMarquee();
}
+ /**
+ * This triggers the TabDocView.PinDoc method which is the universal method
+ * used to pin documents to the currently active presentation trail.
+ *
+ * This one is unique in that it includes the bounds associated with marquee view.
+ */
@undoBatch
@action
- pinWithView = (e: KeyboardEvent | React.PointerEvent | undefined) => {
- const doc = this.props.Document;
- const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc;
- if (curPres) {
- if (doc === curPres) { alert("Cannot pin presentation document to itself"); return; }
- const pinDoc = Doc.MakeAlias(doc);
- pinDoc.presentationTargetDoc = doc;
- pinDoc.presMovement = PresMovement.Zoom;
- pinDoc.groupWithUp = false;
- pinDoc.context = curPres;
- pinDoc.title = doc.title + " - Slide";
- const presArray = PresBox.Instance?.sortArray();
- const size = PresBox.Instance?._selectedArray.size;
- const presSelected = presArray && size ? presArray[size - 1] : undefined;
- Doc.AddDocToList(curPres, "data", pinDoc, presSelected);
- if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
- if (!DocumentManager.Instance.getDocumentView(curPres)) {
- CollectionDockingView.AddSplit(curPres, "right");
- }
- PresBox.Instance?._selectedArray.clear();
- pinDoc && PresBox.Instance?._selectedArray.set(pinDoc, undefined); //Updates selected array
- const index = PresBox.Instance?.childDocs.indexOf(pinDoc);
- index && (curPres._itemIndex = index);
- if (e instanceof KeyboardEvent ? e.key === "c" : true) {
- const scale = Math.min(this.props.PanelWidth() / this.Bounds.width, this.props.PanelHeight() / this.Bounds.height);
- pinDoc.presPinView = true;
- pinDoc.presPinViewX = this.Bounds.left + this.Bounds.width / 2;
- pinDoc.presPinViewY = this.Bounds.top + this.Bounds.height / 2;
- pinDoc.presPinViewScale = scale;
- }
- }
- MarqueeOptionsMenu.Instance.fadeOut(true);
+ pinWithView = async () => {
+ const scale = Math.min(this.props.PanelWidth() / this.Bounds.width, this.props.PanelHeight() / this.Bounds.height);
+ const doc = this.props.Document;
+ const viewOptions:PinViewProps = {
+ bounds: this.Bounds,
+ scale: scale
+ };
+ TabDocView.PinDoc(doc, {pinWithView: viewOptions});
+ MarqueeOptionsMenu.Instance.fadeOut(true);
this.hideMarquee();
}
@@ -519,7 +517,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
d.y = NumCast(d.y) - this.Bounds.top;
return d;
});
- const summary = Docs.Create.TextDocument("", { _backgroundColor: "#e2ad32", x: this.Bounds.left, y: this.Bounds.top, isPushpin: true, _width: 200, _height: 200, _fitToBox: true, _showSidebar: true, title: "overview" });
+ const summary = Docs.Create.TextDocument("", { _backgroundColor: "#e2ad32", x: this.Bounds.left, y: this.Bounds.top, isPushpin: true, _width: 200, _height: 200, _fitContentsToBox: true, _showSidebar: true, title: "overview" });
const portal = Docs.Create.FreeformDocument(selected, { x: this.Bounds.left + 200, y: this.Bounds.top, isGroup: true, backgroundColor: "transparent" });
DocUtils.MakeLink({ doc: summary }, { doc: portal }, "summary of:summarized by", "");
@@ -645,7 +643,7 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
return <div className="marqueeView"
style={{
overflow: StrCast(this.props.Document._overflow),
- cursor: CurrentUserUtils.SelectedTool === InkTool.Pen || CurrentUserUtils.SelectedTool === InkTool.Write ? "crosshair" : "pointer"
+ cursor: [InkTool.Pen, InkTool.Write].includes(CurrentUserUtils.SelectedTool) || this._visible || PresBox.startMarquee ? "crosshair" : "pointer"
}}
onDragOver={e => e.preventDefault()}