From 3415f672292bb349c7d9ec66564933a746ee3b25 Mon Sep 17 00:00:00 2001 From: mehekj Date: Mon, 20 Jun 2022 18:27:29 -0400 Subject: Revert "Merge branch 'master' into temporalmedia-mehek" This reverts commit 145117365b2708ef6b365c6f0f10c38b85a87307, reversing changes made to 7eedde332010c8896be636f0b5c6a7b2c8043e48. --- .../collectionFreeForm/CollectionFreeFormView.tsx | 158 +++++++++------------ .../collections/collectionFreeForm/MarqueeView.tsx | 124 ++++++++++++---- 2 files changed, 160 insertions(+), 122 deletions(-) (limited to 'src/client/views/collections/collectionFreeForm') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 52e99f26b..12ad6b02b 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -9,7 +9,7 @@ import { InkData, InkField, InkTool, PointData, Segment } from "../../../../fiel import { List } from "../../../../fields/List"; import { ObjectField } from "../../../../fields/ObjectField"; import { RichTextField } from "../../../../fields/RichTextField"; -import { listSpec } from "../../../../fields/Schema"; +import { createSchema, listSpec } from "../../../../fields/Schema"; import { ScriptField } from "../../../../fields/ScriptField"; import { BoolCast, Cast, FieldValue, NumCast, ScriptCast, StrCast } from "../../../../fields/Types"; import { ImageField } from "../../../../fields/URLField"; @@ -26,7 +26,6 @@ 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"; @@ -42,7 +41,6 @@ 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"; @@ -52,14 +50,26 @@ 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 e = require("connect-flash"); - +import { FieldView, FieldViewProps } from "../../nodes/FieldView"; + +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) @@ -127,20 +137,16 @@ export class CollectionFreeFormView extends CollectionSubView 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, Cast(this.Document.resolvedDataDoc, Doc, null)); } - @computed get nativeHeight() { return this.fitContentsToBox ? 0 : Doc.NativeHeight(this.Document, Cast(this.Document.resolvedDataDoc, Doc, null)); } + @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 cachedCenteringShiftX(): number { - const scaling = this.fitContentsToBox || !this.contentScaling ? 1 : this.contentScaling; + const scaling = this.fitToContent || !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.fitContentsToBox || !this.contentScaling ? 1 : this.contentScaling; + const scaling = this.fitToContent || !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 { @@ -165,13 +171,11 @@ export class CollectionFreeFormView extends CollectionSubView !this._firstRender && (this.fitContentsToBox || force) ? this.fitToContentVals : undefined; - reverseNativeScaling = () => this.fitContentsToBox ? true : false; - // panx, pany, zoomscale all attempt to get values first from the layout controller, then from the layout/dataDoc (or template layout doc), and finally from the resolved template data document. - // this search order, for example, allows icons of cropped images to find the panx/pany/zoom on the cropped image's data doc instead of the usual layout doc because the zoom/panX/panY define the cropped image - panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document._panX, NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panX, 1)); - panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document._panY, NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.panY, 1)); - zoomScaling = () => this.freeformData()?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.[this.scaleFieldKey], 1)); + freeformData = (force?: boolean) => !this._firstRender && (this.fitToContent || force) ? this.fitToContentVals : undefined; + reverseNativeScaling = () => this.fitToContent ? 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)); contentTransform = () => !this.cachedCenteringShiftX && !this.cachedCenteringShiftY && this.zoomScaling() === 1 ? "" : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`; getTransform = () => this.cachedGetTransform.copy(); getLocalTransform = () => this.cachedGetLocalTransform.copy(); @@ -998,16 +1002,6 @@ export class CollectionFreeFormView extends CollectionSubView pair.layout).filter(doc => doc instanceof Doc); @@ -1234,6 +1228,7 @@ export class CollectionFreeFormView extends CollectionSubView; } addDocTab = action((doc: Doc, where: string) => { @@ -1416,9 +1411,9 @@ export class CollectionFreeFormView extends CollectionSubView { 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); } } if (oldDiv instanceof HTMLCanvasElement) { - if (oldDiv.className === "collectionFreeFormView-grid") { - const newCan = newDiv as HTMLCanvasElement; - const parEle = newCan.parentElement as HTMLElement; - parEle.removeChild(newCan); - parEle.appendChild(document.createElement('div')) - } else { - const canvas = oldDiv; - const img = document.createElement('img'); // create a Image Element - img.src = canvas.toDataURL(); //image source - img.style.width = canvas.style.width; - img.style.height = canvas.style.height; - const newCan = newDiv as HTMLCanvasElement; - const parEle = newCan.parentElement as HTMLElement; - parEle.removeChild(newCan); - parEle.appendChild(img); - } + const canvas = oldDiv; + const img = document.createElement('img'); // create a Image Element + img.src = canvas.toDataURL(); //image source + img.style.width = canvas.style.width; + img.style.height = canvas.style.height; + const newCan = newDiv as HTMLCanvasElement; + const parEle = newCan.parentElement as HTMLElement; + parEle.removeChild(newCan); + parEle.appendChild(img); } } - 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, 1, false, "", - (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, - realNativeHeight: number, - noSuffix: boolean, - replaceRootFilename: string| undefined, - cb:(iconFile:string, nativeWidth:number, nativeHeight:number) => any) - { + updateIcon = () => { + const docViewContent = this.props.docViewPath().lastElement().ContentDiv!; const newDiv = docViewContent.cloneNode(true) as HTMLDivElement; - newDiv.style.width = width.toString(); - newDiv.style.height = height.toString(); + newDiv.style.width = (this.layoutDoc[WidthSym]()).toString(); + newDiv.style.height = (this.layoutDoc[HeightSym]()).toString(); this.replaceCanvases(docViewContent, newDiv); - const htmlString = new XMLSerializer().serializeToString(newDiv); - const nativeWidth = width; - const nativeHeight = height; - return CreateImage( - Utils.prepend(""), + const htmlString = this._mainCont && new XMLSerializer().serializeToString(newDiv); + const nativeWidth = this.layoutDoc[WidthSym](); + const nativeHeight = this.layoutDoc[HeightSym](); + + CreateImage( + "", document.styleSheets, htmlString, nativeWidth, - nativeWidth * panelHeight / panelWidth, - scrollTop * panelHeight / realNativeHeight + nativeWidth * this.props.PanelHeight() / this.props.PanelWidth(), + NumCast(this.layoutDoc._scrollTop) ).then - (async (data_url: any) => { - const returnedFilename = await VideoBox.convertDataUri(data_url, filename, noSuffix, replaceRootFilename); - cb(returnedFilename as string, nativeWidth, nativeHeight); + ((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)); }) .catch(function (error: any) { console.error('oops, something went wrong!', error); @@ -1630,9 +1605,8 @@ export class CollectionFreeFormView extends CollectionSubView { 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.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" }); + 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" }); this.props.ContainingCollectionView && appearanceItems.push({ description: "Ungroup collection", event: this.promoteCollection, icon: "table" }); @@ -1788,7 +1762,7 @@ export class CollectionFreeFormView extends CollectionSubView
{this.layoutDoc._backgroundGridShow ? -
: (null)} + /> : (null)} Transform; @@ -44,14 +43,6 @@ 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 { @@ -70,8 +61,7 @@ export class MarqueeView extends React.Component 100) && !PresBox.startMarquee) { @@ -395,23 +385,98 @@ export class MarqueeView extends React.Component { - 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); + pinMarqueeView = async () => { + const doc = this.props.Document; + const curPres = Cast(Doc.UserDoc().activePresentation, Doc) as Doc; + if (curPres) { + console.log(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";// these should potentially all be props passed down by the CollectionTreeView to the TreeView elements. That way the PresBox could configure all of its children at render time + pinDoc.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area + pinDoc.treeViewHeaderWidth = "100%"; // forces the header to grow to be the same size as its largest sibling. + pinDoc.treeViewChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc. + pinDoc.treeViewFieldKey = "data"; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field + pinDoc.treeViewExpandedView = "data";// in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view + pinDoc.treeViewGrowsHorizontally = true;// the document expands horizontally when displayed as a tree view header + pinDoc.treeViewHideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header + + 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; + const dview = CollectionDockingView.Instance.props.Document; + const fieldKey = CollectionDockingView.Instance.props.fieldKey; + const tabdocs = await DocListCastAsync(dview[fieldKey]); + if (!tabdocs?.includes(curPres)) { + tabdocs?.push(curPres); // bcz: Argh! this is annoying. if multiple documents are pinned, this will get called multiple times before the presentation view is drawn. Thus it won't be in the tabdocs list and it will get created multple times. so need to explicilty add the presbox to the list of open tabs + 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); + 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; + } + this.hideMarquee(); + } + + @undoBatch + @action + pinWithView = async (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"; + pinDoc.treeViewRenderAsBulletHeader = true; // forces a tree view to render the document next to the bullet in the header area + pinDoc.treeViewHeaderWidth = "100%"; // forces the header to grow to be the same size as its largest sibling. + pinDoc.treeViewChildrenOnRoot = true; // tree view will look for hierarchical children on the root doc, not the data doc. + pinDoc.treeViewFieldKey = "data"; // tree view will treat the 'data' field as the field where the hierarchical children are located instead of using the document's layout string field + pinDoc.treeViewExpandedView = "data";// in case the data doc has an expandedView set, this will mask that field and use the 'data' field when expanding the tree view + pinDoc.treeViewGrowsHorizontally = true;// the document expands horizontally when displayed as a tree view header + pinDoc.treeViewHideHeaderIfTemplate = true; // this will force the document to render itself as the tree view header + + 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; const dview = CollectionDockingView.Instance.props.Document; + const fieldKey = CollectionDockingView.Instance.props.fieldKey; + const tabdocs = await DocListCastAsync(dview[fieldKey]); + if (!tabdocs?.includes(curPres)) { + tabdocs?.push(curPres); // bcz: Argh! this is annoying. if multiple documents are pinned, this will get called multiple times before the presentation view is drawn. Thus it won't be in the tabdocs list and it will get created multple times. so need to explicilty add the presbox to the list of open tabs + 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); this.hideMarquee(); } @@ -434,7 +499,6 @@ export class MarqueeView extends React.Component