From 61dcd6a0e23384e68a7d7f2f9e0143741f5cbf56 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 15 May 2020 17:36:39 -0400 Subject: moving toward a proper slide transition system --- src/fields/ScriptField.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'src/fields') diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index f05f431ac..0ac1ac360 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -1,5 +1,5 @@ import { ObjectField } from "./ObjectField"; -import { CompiledScript, CompileScript, scriptingGlobal, ScriptOptions, CompileError, CompileResult } from "../client/util/Scripting"; +import { CompiledScript, CompileScript, scriptingGlobal, ScriptOptions, CompileError, CompileResult, Scripting } from "../client/util/Scripting"; import { Copy, ToScriptString, ToString, Parent, SelfProxy } from "./FieldSymbols"; import { serializable, createSimpleSchema, map, primitive, object, deserialize, PropSchema, custom, SKIP } from "serializr"; import { Deserializable, autoObject } from "../client/util/SerializationHelper"; @@ -156,12 +156,16 @@ export class ComputedField extends ScriptField { return compiled.compiled ? new ComputedField(compiled, setCompiled?.compiled ? setCompiled : undefined) : undefined; } public static MakeInterpolated(fieldKey: string, interpolatorKey: string) { - const getField = ScriptField.CompileScript(`(self['${fieldKey}-indexed'])[self.${interpolatorKey}]`, {}, true, {}); + const getField = ScriptField.CompileScript(`getIndexVal(self['${fieldKey}-indexed'], self.${interpolatorKey})`, {}, true, {}); const setField = ScriptField.CompileScript(`(self['${fieldKey}-indexed'])[self.${interpolatorKey}] = value`, { value: "any" }, true, {}); return getField.compiled ? new ComputedField(getField, setField?.compiled ? setField : undefined) : undefined; } } +Scripting.addGlobal(function getIndexVal(list: any[], index: number) { + return list.reduce((p, x, i) => (i <= index && x !== undefined) || p === undefined ? x : p, undefined as any) +}); + export namespace ComputedField { let useComputed = true; export function DisableComputedFields() { -- cgit v1.2.3-70-g09d2 From ceb616873f76ee19549306a735a09697a56291a2 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 16 May 2020 20:03:34 -0400 Subject: fixed copying of computed fields (bug when aliasing animated collections). fixed opacity for presentation view. renamed timecode to match with video timecodes. --- .../views/collections/CollectionStackingView.tsx | 1 + src/client/views/collections/CollectionSubView.tsx | 1 + src/client/views/collections/CollectionView.tsx | 1 + .../collectionFreeForm/CollectionFreeFormView.tsx | 45 +++++++++++----------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 15 ++++---- src/client/views/nodes/DocumentView.tsx | 5 ++- src/client/views/nodes/PresBox.tsx | 3 +- .../views/presentationview/PresElementBox.tsx | 1 + src/fields/Doc.ts | 2 +- src/fields/ScriptField.ts | 8 +++- 10 files changed, 47 insertions(+), 35 deletions(-) (limited to 'src/fields') diff --git a/src/client/views/collections/CollectionStackingView.tsx b/src/client/views/collections/CollectionStackingView.tsx index cc6077d98..421bf90c1 100644 --- a/src/client/views/collections/CollectionStackingView.tsx +++ b/src/client/views/collections/CollectionStackingView.tsx @@ -213,6 +213,7 @@ export class CollectionStackingView extends CollectionSubView(StackingDocument) onClick={this.onChildClickHandler} onDoubleClick={this.onChildDoubleClickHandler} ScreenToLocalTransform={dxf} + opacity={this.props.childOpacity} focus={this.focusDocument} ContainingCollectionDoc={this.props.CollectionView?.props.Document} ContainingCollectionView={this.props.CollectionView} diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index c9eb08b45..0827f8782 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -44,6 +44,7 @@ export interface SubCollectionViewProps extends CollectionViewProps { CollectionView: Opt; children?: never | (() => JSX.Element[]) | React.ReactNode; ChildLayoutTemplate?: () => Doc; + childOpacity?:() => number; ChildLayoutString?: string; childClickScript?: ScriptField; childDoubleClickScript?: ScriptField; diff --git a/src/client/views/collections/CollectionView.tsx b/src/client/views/collections/CollectionView.tsx index 3b2e5e4fc..acb66acdb 100644 --- a/src/client/views/collections/CollectionView.tsx +++ b/src/client/views/collections/CollectionView.tsx @@ -72,6 +72,7 @@ export interface CollectionViewCustomProps { filterAddDocument: (doc: Doc | Doc[]) => boolean; // allows a document that renders a Collection view to filter or modify any documents added to the collection (see PresBox for an example) childLayoutTemplate?: () => Opt; // specify a layout Doc template to use for children of the collection childLayoutString?: string; // specify a layout string to use for children of the collection + childOpacity?:() => number; } export interface CollectionRenderProps { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d27f3bb0d..e66e95d81 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -54,7 +54,8 @@ export const panZoomSchema = createSchema({ _panX: "number", _panY: "number", scale: "number", - timecode: "number", + currentTimecode: "number", + displayTimecode: "number", arrangeScript: ScriptField, arrangeInit: ScriptField, useClusters: "boolean", @@ -126,8 +127,8 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.Document.timecode !== undefined) { - CollectionFreeFormDocumentView.setupKeyframes((newBox instanceof Doc) ? [newBox] : newBox, this.Document.timecode, this.props.Document); + if (this.Document.currentTimecode !== undefined) { + CollectionFreeFormDocumentView.setupKeyframes((newBox instanceof Doc) ? [newBox] : newBox, this.Document.currentTimecode, this.props.Document); } if (newBox instanceof Doc) { @@ -144,23 +145,24 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.props.Document.timecode === undefined) { - this.props.Document.timecode = 0; + const currentTimecode = this.Document.currentTimecode; + if (currentTimecode === undefined) { + this.Document.currentTimecode = 0; CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0, this.props.Document); } - const timecode = NumCast(this.props.Document.timecode); - CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, timecode); - this.props.Document.timecode = Math.max(0, timecode + 1); + CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, currentTimecode || 0); + this.Document.currentTimecode = Math.max(0, (currentTimecode || 0) + 1); } @undoBatch @action prevKeyframe = (): void => { - if (this.props.Document.timecode === undefined) { - this.props.Document.timecode = 0; + const currentTimecode = this.Document.currentTimecode; + if (currentTimecode === undefined) { + this.Document.currentTimecode = 0; CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0, this.props.Document); } CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice()); - this.props.Document.timecode = Math.max(0, NumCast(this.props.Document.timecode) - 1); + this.Document.currentTimecode = Math.max(0, (currentTimecode || 0) - 1); } private selectDocuments = (docs: Doc[]) => { @@ -203,8 +205,8 @@ export class CollectionFreeFormView extends CollectionSubView) { const layoutDocs = this.childLayoutPairs.map(pair => pair.layout); const initResult = this.Document.arrangeInit && this.Document.arrangeInit.script.run({ docs: layoutDocs, collection: this.Document }, console.log); - const state = initResult && initResult.success ? initResult.result.scriptState : undefined; - const elements = initResult && initResult.success ? this.viewDefsToJSX(initResult.result.views) : []; + const state = initResult?.success ? initResult.result.scriptState : undefined; + const elements = initResult?.success ? this.viewDefsToJSX(initResult.result.views) : []; this.childLayoutPairs.filter(pair => this.isCurrent(pair.layout)).map((pair, i) => { const pos = this.getCalculatedPositions({ pair, index: i, collection: this.Document, docs: layoutDocs, state }); @@ -1075,7 +1074,7 @@ export class CollectionFreeFormView extends CollectionSubView 0 ? this.placeholder : this.marqueeView} - {this.isAnnotationOverlay ? (null) : + {this.isAnnotationOverlay || !this.props.isSelected() ? (null) : <>
- {NumCast(this.props.Document.timecode)} + {NumCast(this.props.Document.currentTimecode)}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index c9bb543f1..5f0e28db2 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -36,11 +36,11 @@ export class CollectionFreeFormDocumentView extends DocComponent (this.sizeProvider?.height || this.props.PanelHeight?.()); getTransform = (): Transform => this.props.ScreenToLocalTransform().translate(-this.X, -this.Y).scale(1 / this.contentScaling()); focusDoc = (doc: Doc) => this.props.focus(doc, false); + opacity = () => this.Opacity; NativeWidth = () => this.nativeWidth; NativeHeight = () => this.nativeHeight; render() { @@ -144,7 +145,6 @@ export class CollectionFreeFormDocumentView extends DocComponent void; backgroundHalo?: () => boolean; backgroundColor?: (doc: Doc) => string | undefined; + opacity?: () => number; ChromeHeight?: () => number; dontRegisterView?: boolean; layoutKey?: string; @@ -1119,6 +1120,8 @@ export class DocumentView extends DocComponent(Docu render() { if (!(this.props.Document instanceof Doc)) return (null); const backgroundColor = Doc.UserDoc().renderStyle === "comic" ? undefined : StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document); + const opacity = Cast(this.layoutDoc._opacity, "number", Cast(this.layoutDoc.opacity, "number", Cast(this.Document.opacity, "number", null))); + const finalOpacity = this.props.opacity ? this.props.opacity() : opacity; const finalColor = this.layoutDoc.type === DocumentType.FONTICON || this.layoutDoc._viewType === CollectionViewType.Linear ? undefined : backgroundColor; const fullDegree = Doc.isBrushedHighlightedDegree(this.props.Document); const borderRounding = this.layoutDoc.borderRounding; @@ -1155,7 +1158,7 @@ export class DocumentView extends DocComponent(Docu border: highlighting && borderRounding ? `${highlightStyles[fullDegree]} ${highlightColors[fullDegree]} ${localScale}px` : undefined, boxShadow: this.props.Document.isTemplateForField ? "black 0.2vw 0.2vw 0.8vw" : undefined, background: finalColor, - opacity: this.Document.opacity, + opacity: finalOpacity, fontFamily: StrCast(this.Document._fontFamily, "inherit"), fontSize: Cast(this.Document._fontSize, "number", null) }}> diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 342a8a215..6edcae417 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -5,7 +5,7 @@ import { observer } from "mobx-react"; import { Doc, DocListCast, DocCastAsync } from "../../../fields/Doc"; import { InkTool } from "../../../fields/InkField"; import { BoolCast, Cast, NumCast, StrCast } from "../../../fields/Types"; -import { returnFalse } from "../../../Utils"; +import { returnFalse, returnOne } from "../../../Utils"; import { documentSchema } from "../../../fields/documentSchemas"; import { DocumentManager } from "../../util/DocumentManager"; import { undoBatch } from "../../util/UndoManager"; @@ -316,6 +316,7 @@ export class PresBox extends ViewBoxBaseComponent PanelWidth={this.props.PanelWidth} PanelHeight={this.panelHeight} moveDocument={returnFalse} + childOpacity={returnOne} childLayoutTemplate={this.childLayoutTemplate} filterAddDocument={this.addDocumentFilter} removeDocument={returnFalse} diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 280ba9093..26c8aa80a 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -177,6 +177,7 @@ export class PresElementBox extends ViewBoxBaseComponent this._lastComputedResult = this.script.run({ this: doc, self: Cast(doc.rootDocument, Doc, null) || doc, _last_: this._lastComputedResult }, console.log).result; + [Copy](): ObjectField { + return new ComputedField(this.script); + } + constructor(script: CompiledScript, setterscript?: CompiledScript) { super(script, - !setterscript && script?.originalScript.includes("self.timecode") ? - ScriptField.CompileScript("self['x' + self.timecode] = value", { value: "any" }, true) : setterscript); + !setterscript && script?.originalScript.includes("self.displayTimecode") ? + ScriptField.CompileScript("self['x' + self.displayTimecode] = value", { value: "any" }, true) : setterscript); } public static MakeScript(script: string, params: object = {}) { -- cgit v1.2.3-70-g09d2 From 2882dfce48e434f0c0b6a5837fc6212cad1df131 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sun, 17 May 2020 19:43:53 -0400 Subject: fixed presentations to step through slides with "animations" --- .../collectionFreeForm/CollectionFreeFormView.tsx | 1 + src/client/views/nodes/PresBox.tsx | 24 +++++++++++++++++----- src/fields/ScriptField.ts | 6 ------ 3 files changed, 20 insertions(+), 11 deletions(-) (limited to 'src/fields') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index e66e95d81..dc7d7918a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -152,6 +152,7 @@ export class CollectionFreeFormView extends CollectionSubView @action next = () => { this.updateCurrentPresentation(); - if (this.childDocs[this.itemIndex + 1] !== undefined) { + const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null); + const lastFrame = Cast(presTargetDoc.lastTimecode, "number", null); + const curFrame = NumCast(presTargetDoc.currentTimecode); + if (lastFrame !== undefined && curFrame < lastFrame) { + presTargetDoc.currentTimecode = curFrame + 1; + } + else if (this.childDocs[this.itemIndex + 1] !== undefined) { let nextSelected = this.itemIndex + 1; this.gotoDocument(nextSelected, this.itemIndex); @@ -188,11 +194,15 @@ export class PresBox extends ViewBoxBaseComponent //The function that is called when a document is clicked or reached through next or back. //it'll also execute the necessary actions if presentation is playing. - public gotoDocument = (index: number, fromDoc: number) => { + public gotoDocument = action((index: number, fromDoc: number) => { this.updateCurrentPresentation(); Doc.UnBrushAllDocs(); if (index >= 0 && index < this.childDocs.length) { this.rootDoc._itemIndex = index; + const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null); + if (presTargetDoc.lastTimecode !== undefined) { + presTargetDoc.currentTimecode = 0; + } if (!this.layoutDoc.presStatus) { this.layoutDoc.presStatus = true; @@ -203,7 +213,7 @@ export class PresBox extends ViewBoxBaseComponent this.hideIfNotPresented(index); this.showAfterPresented(index); } - } + }) //The function that starts or resets presentaton functionally, depending on status flag. startOrResetPres = () => { @@ -286,7 +296,11 @@ export class PresBox extends ViewBoxBaseComponent (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) render() { - this.rootDoc.presOrderedDocs = new List(this.childDocs.map((child, i) => child)); + console.log("render = " + this.layoutDoc.title + " " + this.layoutDoc.presStatus); + const presOrderedDocs = DocListCast(this.rootDoc.presOrderedDocs); + if (presOrderedDocs.length != this.childDocs.length || presOrderedDocs.some((pd, i) => pd !== this.childDocs[i])) { + this.rootDoc.presOrderedDocs = new List(this.childDocs.slice()); + } const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; return
diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 3a4cdbdf8..566390c0d 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -144,12 +144,6 @@ export class ComputedField extends ScriptField { return new ComputedField(this.script); } - constructor(script: CompiledScript, setterscript?: CompiledScript) { - super(script, - !setterscript && script?.originalScript.includes("self.displayTimecode") ? - ScriptField.CompileScript("self['x' + self.displayTimecode] = value", { value: "any" }, true) : setterscript); - } - public static MakeScript(script: string, params: object = {}) { const compiled = ScriptField.CompileScript(script, params, false); return compiled.compiled ? new ComputedField(compiled) : undefined; -- cgit v1.2.3-70-g09d2 From 8de8756e5fa8b7031092c870c84f5214e2a244c1 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 20 May 2020 12:16:56 -0400 Subject: fixed up interaction with web pages to allow horizontal scrolling. --- src/client/documents/Documents.ts | 4 +-- src/client/views/collections/CollectionMapView.tsx | 4 +-- .../collectionFreeForm/CollectionFreeFormView.tsx | 11 +++++-- src/client/views/nodes/DocumentView.tsx | 7 ----- src/client/views/nodes/WebBox.tsx | 35 ++++++++++++---------- src/client/views/pdf/PDFViewer.tsx | 1 - src/fields/documentSchemas.ts | 6 ++-- 7 files changed, 36 insertions(+), 32 deletions(-) (limited to 'src/fields') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 18a0b43ff..b859086d5 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -112,7 +112,7 @@ export interface DocumentOptions { caption?: RichTextField; ignoreClick?: boolean; lockedPosition?: boolean; // lock the x,y coordinates of the document so that it can't be dragged - lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed + _lockedTransform?: boolean; // lock the panx,pany and scale parameters of the document so that it be panned/zoomed isAnnotating?: boolean; // whether we web document is annotation mode where links can't be clicked to allow annotations to be created opacity?: number; defaultBackgroundColor?: string; @@ -635,7 +635,7 @@ export namespace Docs { } export function WebDocument(url: string, options: DocumentOptions = {}) { - return InstanceFromProto(Prototypes.get(DocumentType.WEB), url ? new WebField(new URL(url)) : undefined, { _fitWidth: true, _chromeStatus: url ? "disabled" : "enabled", isAnnotating: true, lockedTransform: true, ...options }); + return InstanceFromProto(Prototypes.get(DocumentType.WEB), url ? new WebField(new URL(url)) : undefined, { _fitWidth: true, _chromeStatus: url ? "disabled" : "enabled", isAnnotating: true, _lockedTransform: true, ...options }); } export function HtmlDocument(html: string, options: DocumentOptions = {}) { diff --git a/src/client/views/collections/CollectionMapView.tsx b/src/client/views/collections/CollectionMapView.tsx index d91337ce9..a0b7cd8a8 100644 --- a/src/client/views/collections/CollectionMapView.tsx +++ b/src/client/views/collections/CollectionMapView.tsx @@ -226,7 +226,7 @@ class CollectionMapView extends CollectionSubView initialCenter={center} center={center} onIdle={(_props?: IMapProps, map?: google.maps.Map) => { - if (this.layoutDoc.lockedTransform) { + if (this.layoutDoc._lockedTransform) { // reset zoom (ideally, we could probably can tell the map to disallow zooming somehow instead) map?.setZoom(center?.zoom || 10); map?.setCenter({ lat: center?.lat!, lng: center?.lng! }); @@ -238,7 +238,7 @@ class CollectionMapView extends CollectionSubView } }} onDragend={(_props?: IMapProps, map?: google.maps.Map) => { - if (this.layoutDoc.lockedTransform) { + if (this.layoutDoc._lockedTransform) { // reset the drag (ideally, we could probably can tell the map to disallow dragging somehow instead) map?.setCenter({ lat: center?.lat!, lng: center?.lng! }); } else { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index c9b3519aa..972c09484 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -769,7 +769,7 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.props.Document.lockedTransform || this.props.Document.inOverlay) return; + if (this.layoutDoc._lockedTransform || this.props.Document.inOverlay) return; if (!e.ctrlKey && this.props.Document.scrollHeight !== undefined) { // things that can scroll vertically should do that instead of zooming e.stopPropagation(); } @@ -805,7 +805,7 @@ export class CollectionFreeFormView extends CollectionSubView { + this.layoutDoc._lockedTransform = this.layoutDoc._lockedTransform ? undefined : true; + } + private thumbIdentifier?: number; onContextMenu = (e: React.MouseEvent) => { @@ -1189,6 +1195,7 @@ export class CollectionFreeFormView extends CollectionSubView this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" }); optionItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" }); this.props.ContainingCollectionView && optionItems.push({ description: "Promote Collection", event: this.promoteCollection, icon: "table" }); + optionItems.push({ description: this.layoutDoc._lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: this.layoutDoc._lockedTransform ? "unlock" : "lock" }); optionItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" }); // layoutItems.push({ description: "Analyze Strokes", event: this.analyzeStrokes, icon: "paint-brush" }); optionItems.push({ diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 34aabfe5e..8dbd0232b 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -683,12 +683,6 @@ export class DocumentView extends DocComponent(Docu this.Document.lockedPosition = this.Document.lockedPosition ? undefined : true; } - @undoBatch - @action - toggleLockTransform = (): void => { - this.Document.lockedTransform = this.Document.lockedTransform ? undefined : true; - } - @action onContextMenu = async (e: React.MouseEvent | Touch): Promise => { // the touch onContextMenu is button 0, the pointer onContextMenu is button 2 @@ -751,7 +745,6 @@ export class DocumentView extends DocComponent(Docu const moreItems: ContextMenuProps[] = more && "subitems" in more ? more.subitems : []; moreItems.push({ description: "Make View of Metadata Field", event: () => Doc.MakeMetadataFieldTemplate(this.props.Document, this.props.DataDoc), icon: "concierge-bell" }); moreItems.push({ description: `${this.Document._chromeStatus !== "disabled" ? "Hide" : "Show"} Chrome`, event: () => this.Document._chromeStatus = (this.Document._chromeStatus !== "disabled" ? "disabled" : "enabled"), icon: "project-diagram" }); - moreItems.push({ description: this.Document.lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: BoolCast(this.Document.lockedTransform) ? "unlock" : "lock" }); moreItems.push({ description: this.Document.lockedPosition ? "Unlock Position" : "Lock Position", event: this.toggleLockPosition, icon: BoolCast(this.Document.lockedPosition) ? "unlock" : "lock" }); if (!ClientUtils.RELEASE) { diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index c1a585bca..1d242d958 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -59,14 +59,19 @@ export class WebBox extends ViewBoxAnnotatableComponent this.layoutDoc.scrollY, - (scrollY) => { - if (scrollY !== undefined) { - this._outerRef.current!.scrollTop = scrollY; + this._reactionDisposer = reaction(() => ({ y: this.layoutDoc.scrollY, x: this.layoutDoc.scrollX }), + ({ x, y }) => { + if (y !== undefined) { + this._outerRef.current!.scrollTop = y; this.layoutDoc.scrollY = undefined; } + if (x !== undefined) { + this._outerRef.current!.scrollLeft = x; + this.layoutDoc.scrollX = undefined; + } }, { fireImmediately: true } ); @@ -76,8 +81,10 @@ export class WebBox extends ViewBoxAnnotatableComponent { - const scroll = e.target?.children?.[0].scrollTop; - this.layoutDoc.scrollTop = this._outerRef.current!.scrollTop = scroll; + const scrollTop = e.target?.children?.[0].scrollTop; + const scrollLeft = e.target?.children?.[0].scrollLeft; + this.layoutDoc.scrollTop = this._outerRef.current!.scrollTop = scrollTop; + this.layoutDoc.scrollLeft = this._outerRef.current!.scrollLeft = scrollLeft; } async componentDidMount() { const urlField = Cast(this.dataDoc[this.props.fieldKey], WebField); @@ -182,14 +189,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { - if (!this.layoutDoc.isAnnotating) { - this.layoutDoc.lockedTransform = false; - this.layoutDoc.isAnnotating = true; - } - else { - this.layoutDoc.lockedTransform = true; - this.layoutDoc.isAnnotating = false; - } + this.layoutDoc.isAnnotating = !this.layoutDoc.isAnnotating; } urlEditor() { @@ -427,7 +427,7 @@ export class WebBox extends ViewBoxAnnotatableComponent); } - scrollXf = () => this.props.ScreenToLocalTransform().translate(0, NumCast(this.props.Document.scrollTop)); + scrollXf = () => this.props.ScreenToLocalTransform().translate(NumCast(this.layoutDoc.scrollLeft), NumCast(this.layoutDoc.scrollTop)); render() { return (
-
+
{ - !this.props.Document.lockedTransform && (this.props.Document.lockedTransform = true); // change the address to be the file address of the PNG version of each page // file address of the pdf const { url: { href } } = Cast(this.dataDoc[this.props.fieldKey], PdfField)!; diff --git a/src/fields/documentSchemas.ts b/src/fields/documentSchemas.ts index cacba43b6..142f7e079 100644 --- a/src/fields/documentSchemas.ts +++ b/src/fields/documentSchemas.ts @@ -20,7 +20,9 @@ export const documentSchema = createSchema({ z: "number", // z "coordinate" - non-zero specifies the overlay layer of a freeformview zIndex: "number", // zIndex of a document in a freeform view scrollY: "number", // "command" to scroll a document to a position on load (the value will be reset to 0 after that ) + scrollX: "number", // "command" to scroll a document to a position on load (the value will be reset to 0 after that ) scrollTop: "number", // scroll position of a scrollable document (pdf, text, web) + scrollLeft: "number", // scroll position of a scrollable document (pdf, text, web) // appearance properties on the layout _autoHeight: "boolean", // whether the height of the document should be computed automatically based on its contents @@ -74,8 +76,8 @@ export const documentSchema = createSchema({ isLinkButton: "boolean", // whether document functions as a link follow button to follow the first link on the document when clicked isBackground: "boolean", // whether document is a background element and ignores input events (can only select with marquee) lockedPosition: "boolean", // whether the document can be moved (dragged) - lockedTransform: "boolean", // whether the document can be panned/zoomed - + _lockedTransform: "boolean",// whether a freeformview can pan/zoom + // drag drop properties dragFactory: Doc, // the document that serves as the "template" for the onDragStart script. ie, to drag out copies of the dragFactory document. dropAction: "string", // override specifying what should happen when this document is dropped (can be "alias", "copy", "move") -- cgit v1.2.3-70-g09d2 From f4b18882d8bd31272d5eb7555c9b80609715b935 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Wed, 20 May 2020 17:56:42 -0400 Subject: cleaned up some warnings --- src/client/documents/Documents.ts | 2 +- src/client/views/MainView.tsx | 2 +- src/client/views/collections/CollectionSubView.tsx | 2 +- src/client/views/nodes/PresBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 2 +- src/fields/ScriptField.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'src/fields') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 7a7cbbb93..b4c11a81b 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -922,7 +922,7 @@ export namespace Docs { layout = AudioBox.LayoutString; } else if (field instanceof InkField) { const { selectedColor, selectedWidth, selectedTool } = InkingControl.Instance; - created = Docs.Create.InkDocument(selectedColor, selectedTool, Number(selectedWidth), (field).inkData, resolved); + created = Docs.Create.InkDocument(selectedColor, selectedTool, selectedWidth, (field).inkData, resolved); layout = InkingStroke.LayoutString; } else if (field instanceof List && field[0] instanceof Doc) { created = Docs.Create.StackingDocument(DocListCast(field), resolved); diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index 50d445473..e306279d5 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -569,7 +569,7 @@ export class MainView extends React.Component { } } Scripting.addGlobal(function freezeSidebar() { MainView.expandFlyout(); }); -Scripting.addGlobal(function toggleComicMode() { Doc.UserDoc().fontFamily = "Comic Sans MS"; Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic" }); +Scripting.addGlobal(function toggleComicMode() { Doc.UserDoc().fontFamily = "Comic Sans MS"; Doc.UserDoc().renderStyle = Doc.UserDoc().renderStyle === "comic" ? undefined : "comic"; }); Scripting.addGlobal(function cloneWorkspace() { const copiedWorkspace = Doc.MakeCopy(Cast(Doc.UserDoc().activeWorkspace, Doc, null), true); const workspaces = Cast(Doc.UserDoc().myWorkspaces, Doc, null); diff --git a/src/client/views/collections/CollectionSubView.tsx b/src/client/views/collections/CollectionSubView.tsx index 208925b1c..53acc15c3 100644 --- a/src/client/views/collections/CollectionSubView.tsx +++ b/src/client/views/collections/CollectionSubView.tsx @@ -332,7 +332,7 @@ export function CollectionSubView(schemaCtor: (doc: Doc) => T, moreProps?: srcWeb = SelectionManager.SelectedDocuments()[0].props.Document; srcUrl = (srcWeb.data as WebField).url.href?.match(/http[s]?:\/\/[^/]*/)?.[0]; } - let reg = new RegExp(Utils.prepend(""), "g"); + const reg = new RegExp(Utils.prepend(""), "g"); const modHtml = srcUrl ? html.replace(reg, srcUrl) : html; const htmlDoc = Docs.Create.HtmlDocument(modHtml, { ...options, title: "-web page-", _width: 300, _height: 300 }); Doc.GetProto(htmlDoc)["data-text"] = text; diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 09c03fb30..80b8e7840 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -213,7 +213,7 @@ export class PresBox extends ViewBoxBaseComponent this.hideIfNotPresented(index); this.showAfterPresented(index); } - }) + }); //The function that starts or resets presentaton functionally, depending on status flag. startOrResetPres = () => { diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index c73b88ef7..f80cea941 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -164,7 +164,7 @@ export class WebBox extends ViewBoxAnnotatableComponent { a = ((a << 5) - a) + b.charCodeAt(0); return a & a }, 0); + return s.split('').reduce((a: any, b: any) => { a = ((a << 5) - a) + b.charCodeAt(0); return a & a; }, 0); } @action submitURL = () => { diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 566390c0d..503c60790 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -161,7 +161,7 @@ export class ComputedField extends ScriptField { } Scripting.addGlobal(function getIndexVal(list: any[], index: number) { - return list.reduce((p, x, i) => (i <= index && x !== undefined) || p === undefined ? x : p, undefined as any) + return list.reduce((p, x, i) => (i <= index && x !== undefined) || p === undefined ? x : p, undefined as any); }); export namespace ComputedField { -- cgit v1.2.3-70-g09d2 From 85c052837d21eb48b3a4f1fa7c95db6703b217d1 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Fri, 22 May 2020 00:59:42 -0400 Subject: got rid of renderLock for piles. fixed drag/drop on piles to place things correctly. made piles store their layoutEngine as a field. fixed layout of piled docs. --- .../views/collections/CollectionPileView.scss | 3 ++ .../views/collections/CollectionPileView.tsx | 59 ++++++++++++---------- .../collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 16 ++++-- src/fields/Doc.ts | 44 ++++++++-------- 5 files changed, 70 insertions(+), 54 deletions(-) (limited to 'src/fields') diff --git a/src/client/views/collections/CollectionPileView.scss b/src/client/views/collections/CollectionPileView.scss index ac874b663..48d07e42b 100644 --- a/src/client/views/collections/CollectionPileView.scss +++ b/src/client/views/collections/CollectionPileView.scss @@ -5,4 +5,7 @@ height: 100%; width: 100%; overflow: visible; + .collectionPileView-innards { + width:100%; + } } diff --git a/src/client/views/collections/CollectionPileView.tsx b/src/client/views/collections/CollectionPileView.tsx index e3bcf2a21..020a87b2e 100644 --- a/src/client/views/collections/CollectionPileView.tsx +++ b/src/client/views/collections/CollectionPileView.tsx @@ -1,18 +1,17 @@ import { action, computed, observable, runInAction } from "mobx"; import { observer } from "mobx-react"; -import { HeightSym, Opt, WidthSym } from "../../../fields/Doc"; +import { HeightSym, Opt, WidthSym, Doc } from "../../../fields/Doc"; import { ScriptField } from "../../../fields/ScriptField"; import { BoolCast, NumCast, StrCast } from "../../../fields/Types"; -import { ContextMenu } from "../ContextMenu"; -import { ContextMenuProps } from "../ContextMenuItem"; import { CollectionFreeFormView } from "./collectionFreeForm/CollectionFreeFormView"; import { CollectionSubView } from "./CollectionSubView"; import "./CollectionPileView.scss"; import React = require("react"); import { setupMoveUpEvents, emptyFunction, returnFalse } from "../../../Utils"; import { SelectionManager } from "../../util/SelectionManager"; -import { UndoManager } from "../../util/UndoManager"; +import { UndoManager, undoBatch } from "../../util/UndoManager"; import { SnappingManager } from "../../util/SnappingManager"; +import { DragManager } from "../../util/DragManager"; @observer export class CollectionPileView extends CollectionSubView(doc => doc) { @@ -20,10 +19,12 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { _doubleTap: boolean | undefined = false; _originalChrome: string = ""; @observable _contentsActive = true; - @observable _layoutEngine = "pass"; @observable _collapsed: boolean = false; @observable _childClickedScript: Opt; componentDidMount() { + if (this.layoutEngine() !== "pass" && this.layoutEngine() !== "starburst") { + this.Document._layoutEngine = "pass"; + } this._originalChrome = StrCast(this.layoutDoc._chromeStatus); this.layoutDoc._chromeStatus = "disabled"; this.layoutDoc.hideFilterView = true; @@ -33,49 +34,54 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { this.layoutDoc._chromeStatus = this._originalChrome; } - layoutEngine = () => this._layoutEngine; + layoutEngine = () => StrCast(this.Document._layoutEngine); @computed get contents() { - return
+ return
; } - - specificMenu = (e: React.MouseEvent) => { - const layoutItems: ContextMenuProps[] = []; - const doc = this.props.Document; - - ContextMenu.Instance.addItem({ description: "Options...", subitems: layoutItems, icon: "eye" }); - } - toggleStarburst = action(() => { - if (this._layoutEngine === 'starburst') { + if (this.layoutEngine() === 'starburst') { const defaultSize = 110; this.layoutDoc._overflow = undefined; + this.childDocs.forEach(d => Doc.iconify(d)); this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - NumCast(this.layoutDoc._starburstPileWidth, defaultSize) / 2; this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - NumCast(this.layoutDoc._starburstPileHeight, defaultSize) / 2; this.layoutDoc._width = NumCast(this.layoutDoc._starburstPileWidth, defaultSize); this.layoutDoc._height = NumCast(this.layoutDoc._starburstPileHeight, defaultSize); - this._layoutEngine = 'pass'; + Doc.pileup(this.childDocs); + this.layoutDoc._panX = 0; + this.layoutDoc._panY = -10; + this.props.Document._layoutEngine = 'pass'; } else { const defaultSize = 25; this.layoutDoc._overflow = 'visible'; !this.layoutDoc._starburstRadius && (this.layoutDoc._starburstRadius = 500); !this.layoutDoc._starburstDocScale && (this.layoutDoc._starburstDocScale = 2.5); - if (this._layoutEngine === 'pass') { + if (this.layoutEngine() === 'pass') { this.rootDoc.x = NumCast(this.rootDoc.x) + this.layoutDoc[WidthSym]() / 2 - defaultSize / 2; this.rootDoc.y = NumCast(this.rootDoc.y) + this.layoutDoc[HeightSym]() / 2 - defaultSize / 2; this.layoutDoc._starburstPileWidth = this.layoutDoc[WidthSym](); this.layoutDoc._starburstPileHeight = this.layoutDoc[HeightSym](); } + this.layoutDoc._panX = this.layoutDoc._panY = 0; this.layoutDoc._width = this.layoutDoc._height = defaultSize; - this._layoutEngine = 'starburst'; + this.props.Document._layoutEngine = 'starburst'; } }); + @undoBatch + @action + onInternalDrop = (e: Event, de: DragManager.DropEvent) => { + if (super.onInternalDrop(e, de)) { + if (de.complete.docDragData) { + Doc.pileup(this.childDocs); + } + } + return true; + } + _undoBatch: UndoManager.Batch | undefined; pointerDown = (e: React.PointerEvent) => { let dist = 0; @@ -107,20 +113,17 @@ export class CollectionPileView extends CollectionSubView(doc => doc) { } onClick = (e: React.MouseEvent) => { - if (e.button === 0 && (this._doubleTap || this.layoutEngine() === "starburst")) { + if (e.button === 0 && this._doubleTap) { SelectionManager.DeselectAll(); this.toggleStarburst(); e.stopPropagation(); } - // else if (this.layoutEngine() === "pass") { - // runInAction(() => this._contentsActive = false); - // setTimeout(action(() => this._contentsActive = true), 300); - // } } render() { - return
{this.contents}
; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 9d880d294..1611b6935 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -1363,7 +1363,7 @@ export class CollectionFreeFormView extends CollectionSubView 0 ? this.placeholder : this.marqueeView} - {this.isAnnotationOverlay || !this.props.isSelected() ? (null) : + {this.isAnnotationOverlay || !this.props.isSelected() || this.props.Document._viewType === CollectionViewType.Pile ? (null) : <>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 993cabc36..00d19752f 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1111,6 +1111,16 @@ export class DocumentView extends DocComponent(Docu }), 400); }); + renderLock() { + return (this.Document.isBackground !== undefined || this.isSelected(false)) && + ((this.Document.type === DocumentType.COL && this.Document._viewType !== CollectionViewType.Pile) || this.Document.type === DocumentType.IMG) && + this.props.renderDepth > 0 && this.props.PanelWidth() > 0 ? +
this.toggleBackground(true)}> + +
+ : (null); + } + render() { if (!(this.props.Document instanceof Doc)) return (null); const backgroundColor = Doc.UserDoc().renderStyle === "comic" ? undefined : StrCast(this.layoutDoc._backgroundColor) || StrCast(this.layoutDoc.backgroundColor) || StrCast(this.Document.backgroundColor) || this.props.backgroundColor?.(this.Document); @@ -1161,11 +1171,7 @@ export class DocumentView extends DocComponent(Docu
: this.innards} - {(this.Document.isBackground !== undefined || this.isSelected(false)) && (this.Document.type === DocumentType.COL || this.Document.type === DocumentType.IMG) && this.props.renderDepth > 0 && this.props.PanelWidth() > 0 ? -
this.toggleBackground(true)}> - -
- : (null)} + {this.renderLock()}
; { this._showKPQuery ? : undefined; } } diff --git a/src/fields/Doc.ts b/src/fields/Doc.ts index 9f38f4369..1ea686cbb 100644 --- a/src/fields/Doc.ts +++ b/src/fields/Doc.ts @@ -1028,28 +1028,32 @@ export namespace Doc { if (layoutKey && layoutKey !== "layout" && layoutKey !== "layout_icon") doc.deiconifyLayout = layoutKey.replace("layout_", ""); } - export function pileup(selected: Doc[], x: number, y: number) { - const newCollection = Docs.Create.PileDocument(selected, { title: "pileup", x: x - 55, y: y - 55, _width: 110, _height: 100, _LODdisable: true }); + export function pileup(docList: Doc[], x?: number, y?: number) { let w = 0, h = 0; - selected.forEach((d, i) => { - Doc.iconify(d); - w = Math.max(d[WidthSym](), w); - h = Math.max(d[HeightSym](), h); - }); - h = Math.max(h, w * 4 / 3); // converting to an icon does not update the height right away. so this is a fallback hack to try to do something reasonable - selected.forEach((d, i) => { - d.x = Math.cos(Math.PI * 2 * i / selected.length) * 10 - w / 2; - d.y = Math.sin(Math.PI * 2 * i / selected.length) * 10 - h / 2; - d.displayTimecode = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection + runInAction(() => { + docList.forEach(d => { + Doc.iconify(d); + w = Math.max(d[WidthSym](), w); + h = Math.max(d[HeightSym](), h); + }); + h = Math.max(h, w * 4 / 3); // converting to an icon does not update the height right away. so this is a fallback hack to try to do something reasonable + docList.forEach((d, i) => { + d.x = Math.cos(Math.PI * 2 * i / docList.length) * 10 - w / 2; + d.y = Math.sin(Math.PI * 2 * i / docList.length) * 10 - h / 2; + d.displayTimecode = undefined; // bcz: this should be automatic somehow.. along with any other properties that were logically associated with the original collection + }); }); - newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - 55; - newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - 55; - newCollection._width = newCollection._height = 110; - //newCollection.borderRounding = "40px"; - newCollection._jitterRotation = 10; - newCollection._backgroundColor = "gray"; - newCollection._overflow = "visible"; - return newCollection; + if (x !== undefined && y !== undefined) { + const newCollection = Docs.Create.PileDocument(docList, { title: "pileup", x: x - 55, y: y - 55, _width: 110, _height: 100, _LODdisable: true }); + newCollection.x = NumCast(newCollection.x) + NumCast(newCollection._width) / 2 - 55; + newCollection.y = NumCast(newCollection.y) + NumCast(newCollection._height) / 2 - 55; + newCollection._width = newCollection._height = 110; + //newCollection.borderRounding = "40px"; + newCollection._jitterRotation = 10; + newCollection._backgroundColor = "gray"; + newCollection._overflow = "visible"; + return newCollection; + } } -- cgit v1.2.3-70-g09d2 From 43818b137486f3d4431e1c3b9f4de0b0aefba9ca Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 23 May 2020 14:59:01 -0400 Subject: several fixes to progressivization and added UI for editing by suspending transparency --- .../collectionFreeForm/CollectionFreeFormView.scss | 9 ++++ .../collectionFreeForm/CollectionFreeFormView.tsx | 50 +++++++++++++++------- .../collections/collectionFreeForm/MarqueeView.tsx | 4 +- .../views/nodes/CollectionFreeFormDocumentView.tsx | 14 +++--- src/client/views/nodes/KeyValuePair.tsx | 4 +- .../views/presentationview/PresElementBox.tsx | 5 +-- src/fields/ScriptField.ts | 17 ++++---- src/fields/util.ts | 2 +- 8 files changed, 66 insertions(+), 39 deletions(-) (limited to 'src/fields') diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index 7a84fcde1..5478a1c4a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -51,12 +51,21 @@ } .backKeyframe { right:45; + svg { + display:block; + margin:auto; + } } .numKeyframe { right:25; + text-align:center; } .fwdKeyframe { right:5; + svg { + display:block; + margin:auto; + } } .collectionfreeformview-placeholder { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 4b218bc18..d0415f77d 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -126,21 +126,39 @@ export class CollectionFreeFormView extends CollectionSubView { - if (this.Document.currentTimecode !== undefined && !this.props.isAnnotationOverlay) { - CollectionFreeFormDocumentView.setupKeyframes((newBox instanceof Doc) ? [newBox] : newBox, this.Document.currentTimecode, this.props.Document); - } - + addDocument = action((newBox: Doc | Doc[]) => { + let retVal = false; if (newBox instanceof Doc) { - const added = this.props.addDocument(newBox); - added && this.bringToFront(newBox); - added && this.updateCluster(newBox); - return added; + retVal = this.props.addDocument(newBox); + retVal && this.bringToFront(newBox); + retVal && this.updateCluster(newBox); } else { - return this.props.addDocument(newBox); + retVal = this.props.addDocument(newBox); // bcz: deal with clusters } - } + if (retVal) { + const newBoxes = (newBox instanceof Doc) ? [newBox] : newBox; + for (let i = 0; i < newBoxes.length; i++) { + const newBox = newBoxes[i]; + if (newBox.displayTimecode !== undefined) { + const x = newBox.x; + const y = newBox.y; + delete newBox["x-indexed"]; + delete newBox["y-indexed"]; + delete newBox["opacity-indexed"]; + delete newBox.x; + delete newBox.y; + delete newBox.displayTimecode; + newBox.x = x; + newBox.y = y; + } + } + if (this.Document.currentTimecode !== undefined && !this.props.isAnnotationOverlay) { + CollectionFreeFormDocumentView.setupKeyframes(newBoxes, this.Document.currentTimecode); + } + } + return retVal; + }) @undoBatch @action @@ -148,7 +166,7 @@ export class CollectionFreeFormView extends CollectionSubView
-
- {NumCast(this.props.Document.currentTimecode)} +
this.Document.editing = !this.Document.editing)} > + {NumCast(this.Document.currentTimecode)}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx index c99e74ccd..ed70ac9e8 100644 --- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx +++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx @@ -334,9 +334,7 @@ export class MarqueeView extends React.Component d.context = newCollection); this.hideMarquee(); return newCollection; } diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index a4120f958..88fbdd589 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -77,6 +77,8 @@ export class CollectionFreeFormDocumentView extends DocComponent docs.forEach(doc => doc.transition = undefined), 1010); } - public static setupKeyframes(docs: Doc[], timecode: number, collection: Doc) { + public static setupKeyframes(docs: Doc[], timecode: number, progressivize: boolean = false) { docs.forEach((doc, i) => { + const curTimecode = progressivize ? i : timecode; const xlist = new List(numberRange(timecode + 1).map(i => undefined) as any as number[]); const ylist = new List(numberRange(timecode + 1).map(i => undefined) as any as number[]); - xlist[Math.max(i - 1)] = xlist[timecode + 1] = NumCast(doc.x); - ylist[Math.max(i - 1)] = ylist[timecode + 1] = NumCast(doc.y); + const olist = new List(numberRange(timecode + 1).map(t => progressivize && t < i ? 0 : 1)); + xlist[Math.max(curTimecode - 1, 0)] = xlist[curTimecode] = NumCast(doc.x); + ylist[Math.max(curTimecode - 1, 0)] = ylist[curTimecode] = NumCast(doc.y); doc["x-indexed"] = xlist; doc["y-indexed"] = ylist; - doc["opacity-indexed"] = new List(numberRange(timecode).map(i => 1)); - doc.displayTimecode = ComputedField.MakeFunction("collection ? collection.currentTimecode : 0", {}, { collection }); + doc["opacity-indexed"] = olist; + doc.displayTimecode = ComputedField.MakeFunction("self.context ? (self.context.currentTimecode||0) : 0"); doc.x = ComputedField.MakeInterpolated("x", "displayTimecode"); doc.y = ComputedField.MakeInterpolated("y", "displayTimecode"); doc.opacity = ComputedField.MakeInterpolated("opacity", "displayTimecode"); diff --git a/src/client/views/nodes/KeyValuePair.tsx b/src/client/views/nodes/KeyValuePair.tsx index 956d6556b..3cbe3e494 100644 --- a/src/client/views/nodes/KeyValuePair.tsx +++ b/src/client/views/nodes/KeyValuePair.tsx @@ -99,9 +99,9 @@ export class KeyValuePair extends React.Component {
diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 526a3dbf4..364c1d060 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -101,12 +101,11 @@ export class PresElementBox extends ViewBoxBaseComponent i && numberRange(i).forEach(f => Cast(d["opacity-indexed"], listSpec("number"), [])[f] = 0)); } /** diff --git a/src/fields/ScriptField.ts b/src/fields/ScriptField.ts index 503c60790..5192af407 100644 --- a/src/fields/ScriptField.ts +++ b/src/fields/ScriptField.ts @@ -65,14 +65,14 @@ export class ScriptField extends ObjectField { @serializable(autoObject()) private captures?: ProxyField; - constructor(script: CompiledScript, setterscript?: CompileResult) { + constructor(script: CompiledScript, setterscript?: CompiledScript) { super(); if (script?.options.capturedVariables) { const doc = Doc.assign(new Doc, script.options.capturedVariables); this.captures = new ProxyField(doc); } - this.setterscript = setterscript?.compiled ? setterscript : undefined; + this.setterscript = setterscript; this.script = script; } @@ -98,10 +98,10 @@ export class ScriptField extends ObjectField { // } [Copy](): ObjectField { - return new ScriptField(this.script); + return new ScriptField(this.script, this.setterscript); } toString() { - return `${this.script.originalScript}`; + return `${this.script.originalScript} + ${this.setterscript?.originalScript}`; } [ToScriptString]() { @@ -141,22 +141,21 @@ export class ComputedField extends ScriptField { [Copy](): ObjectField { - return new ComputedField(this.script); + return new ComputedField(this.script, this.setterscript); } public static MakeScript(script: string, params: object = {}) { const compiled = ScriptField.CompileScript(script, params, false); return compiled.compiled ? new ComputedField(compiled) : undefined; } - public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }, setterScript?: string) { + public static MakeFunction(script: string, params: object = {}, capturedVariables?: { [name: string]: Field }) { const compiled = ScriptField.CompileScript(script, params, true, capturedVariables); - const setCompiled = setterScript ? ScriptField.CompileScript(setterScript, params, true, capturedVariables) : undefined; - return compiled.compiled ? new ComputedField(compiled, setCompiled?.compiled ? setCompiled : undefined) : undefined; + return compiled.compiled ? new ComputedField(compiled) : undefined; } public static MakeInterpolated(fieldKey: string, interpolatorKey: string) { const getField = ScriptField.CompileScript(`getIndexVal(self['${fieldKey}-indexed'], self.${interpolatorKey})`, {}, true, {}); const setField = ScriptField.CompileScript(`(self['${fieldKey}-indexed'])[self.${interpolatorKey}] = value`, { value: "any" }, true, {}); - return getField.compiled ? new ComputedField(getField, setField?.compiled ? setField : undefined) : undefined; + return getField.compiled && setField.compiled ? new ComputedField(getField, setField) : undefined; } } diff --git a/src/fields/util.ts b/src/fields/util.ts index a287b0210..024c0f80e 100644 --- a/src/fields/util.ts +++ b/src/fields/util.ts @@ -116,7 +116,7 @@ export function setter(target: any, in_prop: string | symbol | number, value: an return true; } } - if (target.__fields[prop] instanceof ComputedField && target.__fields[prop].setterscript) { + if (target.__fields[prop] instanceof ComputedField && target.__fields[prop].setterscript && value !== undefined && !(value instanceof ComputedField)) { return ScriptCast(target.__fields[prop])?.setterscript?.run({ self: target[SelfProxy], this: target[SelfProxy], value }).success ? true : false; } return _setter(target, prop, value, receiver); -- cgit v1.2.3-70-g09d2 From 2ba063ff94a04e89ee1fa1fde7d71a839f5d6856 Mon Sep 17 00:00:00 2001 From: Bob Zeleznik Date: Sat, 23 May 2020 23:25:22 -0400 Subject: switched frame animations to use currentFrame and activeFrame to fix aliasing issue of progressive slides at different frame codes --- src/client/documents/Documents.ts | 2 ++ src/client/views/MainView.tsx | 6 +--- .../collectionFreeForm/CollectionFreeFormView.tsx | 41 +++++++++++----------- .../views/nodes/CollectionFreeFormDocumentView.tsx | 25 +++++++------ src/client/views/nodes/PresBox.tsx | 6 ++-- .../views/presentationview/PresElementBox.tsx | 2 +- src/fields/documentSchemas.ts | 6 ++-- 7 files changed, 46 insertions(+), 42 deletions(-) (limited to 'src/fields') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 6b17b4303..2be961108 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -126,6 +126,8 @@ export interface DocumentOptions { curPage?: number; currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video) value is in seconds displayTimecode?: number; // the time that a document should be displayed (e.g., time an annotation should be displayed on a video) + currentFrame?: number; // the current frame of a frame-based collection (e.g., progressive slide) + activeFrame?: number; // the active frame of a document in a frame base collection borderRounding?: string; boxShadow?: string; dontRegisterChildViews?: boolean; diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index b7a75dfb9..358de2333 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -139,10 +139,7 @@ export class MainView extends React.Component { initEventListeners = () => { window.addEventListener("drop", (e) => { e.preventDefault(); }, false); // drop event handler - window.addEventListener("dragover", (e) => { - console.log("MDRAG"); - e.preventDefault(); - }, false); // drag event handler + window.addEventListener("dragover", (e) => { e.preventDefault(); }, false); // drag event handler // click interactions for the context menu document.addEventListener("pointerdown", this.globalPointerDown); document.addEventListener("pointerup", this.globalPointerUp); @@ -246,7 +243,6 @@ export class MainView extends React.Component { onDrop = (e: React.DragEvent) => { e.preventDefault(); e.stopPropagation(); - console.log("Drop"); } @action diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index d0415f77d..91e257f80 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -56,6 +56,7 @@ export const panZoomSchema = createSchema({ scale: "number", currentTimecode: "number", displayTimecode: "number", + currentFrame: "number", arrangeScript: ScriptField, arrangeInit: ScriptField, useClusters: "boolean", @@ -140,7 +141,7 @@ export class CollectionFreeFormView extends CollectionSubView { - const currentTimecode = this.Document.currentTimecode; - if (currentTimecode === undefined) { - this.Document.currentTimecode = 0; + const currentFrame = this.Document.currentFrame; + if (currentFrame === undefined) { + this.Document.currentFrame = 0; CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0); } - CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, currentTimecode || 0); - this.Document.currentTimecode = Math.max(0, (currentTimecode || 0) + 1); - this.Document.lastTimecode = Math.max(NumCast(this.Document.currentTimecode), NumCast(this.Document.lastTimecode)); + CollectionFreeFormDocumentView.updateKeyframe(this.childDocs, currentFrame || 0); + this.Document.currentFrame = Math.max(0, (currentFrame || 0) + 1); + this.Document.lastTimecode = Math.max(NumCast(this.Document.currentFrame), NumCast(this.Document.lastTimecode)); } @undoBatch @action prevKeyframe = (): void => { - const currentTimecode = this.Document.currentTimecode; - if (currentTimecode === undefined) { - this.Document.currentTimecode = 0; + const currentFrame = this.Document.currentFrame; + if (currentFrame === undefined) { + this.Document.currentFrame = 0; CollectionFreeFormDocumentView.setupKeyframes(this.childDocs, 0); } CollectionFreeFormDocumentView.gotoKeyframe(this.childDocs.slice()); - this.Document.currentTimecode = Math.max(0, (currentTimecode || 0) - 1); + this.Document.currentFrame = Math.max(0, (currentFrame || 0) - 1); } private selectDocuments = (docs: Doc[]) => { @@ -232,9 +233,9 @@ export class CollectionFreeFormView extends CollectionSubView
this.Document.editing = !this.Document.editing)} > - {NumCast(this.Document.currentTimecode)} + {NumCast(this.Document.currentFrame)}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index 88fbdd589..682aed8f5 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -69,21 +69,24 @@ export class CollectionFreeFormDocumentView extends DocComponent (i <= time && x !== undefined) || p === undefined ? x : p, undefined as any as number), - y: Cast(doc["y-indexed"], listSpec("number"), []).reduce((p, y, i) => (i <= time && y !== undefined) || p === undefined ? y : p, undefined as any as number), - opacity: Cast(doc["opacity-indexed"], listSpec("number"), []).reduce((p, o, i) => i <= time || p === undefined ? o : p, undefined as any as number), + x: Cast(doc["x-indexed"], listSpec("number"), []).reduce((p, x, i) => (i <= timecode && x !== undefined) || p === undefined ? x : p, undefined as any as number), + y: Cast(doc["y-indexed"], listSpec("number"), []).reduce((p, y, i) => (i <= timecode && y !== undefined) || p === undefined ? y : p, undefined as any as number), + opacity: Cast(doc["opacity-indexed"], listSpec("number"), []).reduce((p, o, i) => i <= timecode || p === undefined ? o : p, undefined as any as number), }); } - public static setValues(timecode: number, d: Doc, x?: number, y?: number, opacity?: number) { + public static setValues(time: number, d: Doc, x?: number, y?: number, opacity?: number) { + const timecode = Math.round(time); Cast(d["x-indexed"], listSpec("number"), [])[Math.max(0, timecode - 1)] = x as any as number; - Cast(d["y-indexed"], listSpec("number"), null)[Math.max(0, timecode - 1)] = y as any as number; + Cast(d["y-indexed"], listSpec("number"), [])[Math.max(0, timecode - 1)] = y as any as number; Cast(d["x-indexed"], listSpec("number"), [])[timecode] = x as any as number; - Cast(d["y-indexed"], listSpec("number"), null)[timecode] = y as any as number; + Cast(d["y-indexed"], listSpec("number"), [])[timecode] = y as any as number; Cast(d["opacity-indexed"], listSpec("number"), null)[timecode] = opacity as any as number; } - public static updateKeyframe(docs: Doc[], timecode: number) { + public static updateKeyframe(docs: Doc[], time: number) { + const timecode = Math.round(time); docs.forEach(doc => { const xindexed = Cast(doc['x-indexed'], listSpec("number"), null); const yindexed = Cast(doc['y-indexed'], listSpec("number"), null); @@ -112,10 +115,10 @@ export class CollectionFreeFormDocumentView extends DocComponent this.updateCurrentPresentation(); const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null); const lastFrame = Cast(presTargetDoc.lastTimecode, "number", null); - const curFrame = NumCast(presTargetDoc.currentTimecode); + const curFrame = NumCast(presTargetDoc.currentFrame); if (lastFrame !== undefined && curFrame < lastFrame) { - presTargetDoc.currentTimecode = curFrame + 1; + presTargetDoc.currentFrame = curFrame + 1; } else if (this.childDocs[this.itemIndex + 1] !== undefined) { let nextSelected = this.itemIndex + 1; @@ -200,7 +200,7 @@ export class PresBox extends ViewBoxBaseComponent this.rootDoc._itemIndex = index; const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null); if (presTargetDoc.lastTimecode !== undefined) { - presTargetDoc.currentTimecode = 0; + presTargetDoc.currentFrame = 0; } if (!this.layoutDoc.presStatus) { diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 364c1d060..31ffde8af 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -102,7 +102,7 @@ export class PresElementBox extends ViewBoxBaseComponent Date: Sat, 23 May 2020 23:59:34 -0400 Subject: renamed lastTimecode to lastFrame --- src/client/documents/Documents.ts | 1 + .../views/collections/collectionFreeForm/CollectionFreeFormView.tsx | 2 +- src/client/views/nodes/PresBox.tsx | 4 ++-- src/client/views/presentationview/PresElementBox.tsx | 2 +- src/fields/documentSchemas.ts | 1 + 5 files changed, 6 insertions(+), 4 deletions(-) (limited to 'src/fields') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index 2be961108..7f5b62f22 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -127,6 +127,7 @@ export interface DocumentOptions { currentTimecode?: number; // the current timecode of a time-based document (e.g., current time of a video) value is in seconds displayTimecode?: number; // the time that a document should be displayed (e.g., time an annotation should be displayed on a video) currentFrame?: number; // the current frame of a frame-based collection (e.g., progressive slide) + lastFrame?: number; // the last frame of a frame-based collection (e.g., progressive slide) activeFrame?: number; // the active frame of a document in a frame base collection borderRounding?: string; boxShadow?: string; diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 91e257f80..4840bb7e7 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -171,7 +171,7 @@ export class CollectionFreeFormView extends CollectionSubView next = () => { this.updateCurrentPresentation(); const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null); - const lastFrame = Cast(presTargetDoc.lastTimecode, "number", null); + const lastFrame = Cast(presTargetDoc.lastFrame, "number", null); const curFrame = NumCast(presTargetDoc.currentFrame); if (lastFrame !== undefined && curFrame < lastFrame) { presTargetDoc.currentFrame = curFrame + 1; @@ -199,7 +199,7 @@ export class PresBox extends ViewBoxBaseComponent if (index >= 0 && index < this.childDocs.length) { this.rootDoc._itemIndex = index; const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null); - if (presTargetDoc.lastTimecode !== undefined) { + if (presTargetDoc.lastFrame !== undefined) { presTargetDoc.currentFrame = 0; } diff --git a/src/client/views/presentationview/PresElementBox.tsx b/src/client/views/presentationview/PresElementBox.tsx index 31ffde8af..475fef5b2 100644 --- a/src/client/views/presentationview/PresElementBox.tsx +++ b/src/client/views/presentationview/PresElementBox.tsx @@ -104,7 +104,7 @@ export class PresElementBox extends ViewBoxBaseComponent