From d0025200b23f57ec25d3452d425de8725a032c6a Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Fri, 22 Jan 2021 21:14:37 -0500
Subject: fixed selection bounds for video box annotations, especially when in
 full screen view.

---
 src/client/views/nodes/DocumentView.tsx | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

(limited to 'src/client/views/nodes/DocumentView.tsx')

diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 6217f473f..e3da48749 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -410,7 +410,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                     if (!Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-undo"] as Doc) &&
                         !Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-redo"] as Doc) &&
                         !this.onClickHandler.script.originalScript.includes("selectMainMenu")) {
-                        UndoManager.RunInBatch(func, "on click");
+                        UndoManager.RunInBatch(() => func().result === true ? this.props.select(false) : "", "on click");
                     } else func();
                 };
                 if (this.onDoubleClickHandler) {
@@ -935,7 +935,9 @@ export class DocumentView extends React.Component<DocumentViewProps> {
     PanelWidth = () => this.panelWidth;
     PanelHeight = () => this.panelHeight;
     ContentScale = () => this.nativeScaling;
-    screenToLocalTransform = () => this.props.ScreenToLocalTransform().translate(-this.centeringX, -this.centeringY).scale(1 / this.nativeScaling);
+    screenToLocalTransform = () => {
+        return this.props.ScreenToLocalTransform().translate(-this.centeringX, -this.centeringY).scale(1 / this.nativeScaling);
+    }
 
     componentDidMount() {
         !BoolCast(this.props.Document.dontRegisterView, this.props.dontRegisterView) && DocumentManager.Instance.AddView(this);
-- 
cgit v1.2.3-70-g09d2


From 5a7e3df397e06fffee6a05e57f109714be184034 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 25 Jan 2021 14:01:36 -0500
Subject: fixed linking to video to create an anchor if the timecode is not
 zero.

---
 src/client/util/LinkManager.ts          |  3 +-
 src/client/views/nodes/AudioBox.tsx     |  8 ++--
 src/client/views/nodes/DocumentView.tsx |  2 +-
 src/client/views/nodes/VideoBox.tsx     | 70 +++++++++++++++++----------------
 4 files changed, 43 insertions(+), 40 deletions(-)

(limited to 'src/client/views/nodes/DocumentView.tsx')

diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index accf53676..bf927c5b8 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -54,7 +54,8 @@ export class LinkManager {
     }, true);
 
     relatedLinker = computedFn(function relatedLinker(this: any, anchor: Doc): Doc[] {
-        return DocListCast(anchor[Doc.LayoutFieldKey(anchor) + "-annotations"]).reduce((list, anno) =>
+        const lfield = Doc.LayoutFieldKey(anchor);
+        return DocListCast(anchor[lfield + "-annotations"]).concat(DocListCast(anchor[lfield + "-annotations-timeline"])).reduce((list, anno) =>
             [...list, ...LinkManager.Instance.relatedLinker(anno)],
             LinkManager.Instance.directLinker(anchor).slice());
     }, true);
diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index e854d40be..8614200de 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -108,16 +108,16 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         return { la1, la2, linkTime };
     }
 
+    getAnchor = () => {
+        return this.createMarker(this._ele?.currentTime || Cast(this.props.Document._currentTimecode, "number", null) || (this.audioState === "recording" ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined));
+    }
+
     componentWillUnmount() {
         Object.values(this._disposers).forEach(disposer => disposer?.());
         const ind = DocUtils.ActiveRecordings.indexOf(this);
         ind !== -1 && (DocUtils.ActiveRecordings.splice(ind, 1));
     }
 
-    getAnchor = () => {
-        return this.createMarker(this._ele?.currentTime || Cast(this.props.Document._currentTimecode, "number", null) || (this.audioState === "recording" ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined));
-    }
-
     @action
     componentDidMount() {
         this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document.  this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index e3da48749..6620614f8 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -541,7 +541,7 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
 
     @undoBatch @action
     drop = async (e: Event, de: DragManager.DropEvent) => {
-        if (this.props.LayoutTemplateString) return;
+        if (this.props.dontRegisterView || this.props.LayoutTemplateString?.includes(LinkAnchorBox.name)) return;
         if (this.props.Document === CurrentUserUtils.ActiveDashboard) {
             alert((e.target as any)?.closest?.("*.lm_content") ?
                 "You can't perform this move most likely because you don't have permission to modify the destination." :
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index c5e61eedd..6ca4a589a 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -28,7 +28,6 @@ import { LinkDocPreview } from "./LinkDocPreview";
 import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment";
 import { StyleProp } from "../StyleProvider";
 import { computedFn } from "mobx-utils";
-import { DocumentManager } from "../../util/DocumentManager";
 import { Dictionary } from "typescript-collections";
 import { MarqueeAnnotator } from "../MarqueeAnnotator";
 import { Id } from "../../../fields/FieldSymbols";
@@ -78,14 +77,14 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
     @observable _playTimer?: NodeJS.Timeout = undefined;
     @observable _fullScreen = false;
     @observable _playing = false;
+    @computed get links() { return DocListCast(this.dataDoc.links); }
     @computed get heightPercent() { return this.layoutDoc._showTimeline ? NumCast(this.layoutDoc._videoTimelineHeightPercent, VideoBox.heightPercent) : 100; }
     @computed get videoDuration() { return NumCast(this.dataDoc[this.fieldKey + "-duration"]); }
     @computed get markerDocs() { return DocListCast(this.dataDoc[this.annotationKey + "-timeline"]).concat(DocListCast(this.dataDoc[this.annotationKey])); }
+
     public static LayoutString(fieldKey: string) { return FieldView.LayoutString(VideoBox, fieldKey); }
 
-    public get player(): HTMLVideoElement | null {
-        return this._videoRef;
-    }
+    public get player(): HTMLVideoElement | null { return this._videoRef; }
 
     constructor(props: Readonly<FieldViewProps>) {
         super(props);
@@ -98,6 +97,14 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
         VideoBox.LabelPlayScript = VideoBox.LabelPlayScript || ScriptField.MakeFunction(`scriptContext.playOnClick(self, this.displayTimecode)`, { self: Doc.name, scriptContext: "any" })!;
     }
 
+    getAnchor = () => {
+        return this.createMarker(Cast(this.layoutDoc._currentTimecode, "number", null));
+    }
+
+    choosePath(url: string) {
+        return url.indexOf(window.location.origin) === -1 ? Utils.CorsProxy(url) : url;
+    }
+
     videoLoad = () => {
         const aspect = this.player!.videoWidth / this.player!.videoHeight;
         Doc.SetNativeWidth(this.dataDoc, this.player!.videoWidth);
@@ -154,13 +161,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
         }
     }
 
-    choosePath(url: string) {
-        if (url.indexOf(window.location.origin) === -1) {
-            return Utils.CorsProxy(url);
-        }
-        return url;
-    }
-
     @action public Snapshot() {
         const width = (this.layoutDoc._width || 0);
         const height = (this.layoutDoc._height || 0);
@@ -230,6 +230,8 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
     }
 
     componentDidMount() {
+        this.props.setContentView?.(this); // this tells the DocumentView that this AudioBox is the "content" of the document.  this allows the DocumentView to indirectly call getAnchor() on the AudioBox when making a link.
+
         this._disposers.selection = reaction(() => this.props.isSelected(),
             selected => {
                 if (!selected) {
@@ -239,29 +241,19 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
             },
             { fireImmediately: true });
         this._disposers.videoStart = reaction(
-            () => this.Document._videoStart,
-            (videoStart) => {
-                if (videoStart !== undefined) {
-                    if (this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) {
-                        const delay = this.player ? 0 : 250; // wait for mainCont and try again to play
-                        setTimeout(() => this.player && this.Play(), delay);
-                        setTimeout(() => this.Document._videoStart = undefined, 10 + delay);
-                    }
-                }
-            },
+            () => !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc && this.props.renderDepth !== -1 ? Cast(this.Document._videoStart, "number", null) : undefined,
+            videoStart => videoStart !== undefined && setTimeout(() => {
+                this.player && this.Play();
+                setTimeout(() => this.Document._videoStart = undefined, 10);
+            }, this.player ? 0 : 250), // wait for mainCont and try again to play
             { fireImmediately: true }
         );
         this._disposers.videoStop = reaction(
-            () => this.Document._videoStop,
-            (videoStop) => {
-                if (videoStop !== undefined) {
-                    if (this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) {
-                        const delay = this.player ? 0 : 250; // wait for mainCont and try again to play
-                        setTimeout(() => this.player && this.Pause(), delay);
-                        setTimeout(() => { this.Document._videoStop = undefined; }, 10 + delay);
-                    }
-                }
-            },
+            () => this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc ? Cast(this.Document._videoStop, "number", null) : undefined,
+            videoStop => videoStop !== undefined && setTimeout(() => {
+                this.player && this.Pause();
+                setTimeout(() => this.Document._videoStop = undefined, 10);
+            }, this.player ? 0 : 250), // wait for mainCont and try again to play
             { fireImmediately: true }
         );
         if (this.youtubeVideoId) {
@@ -334,7 +326,6 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
         }
     }
 
-    // returns the video and timeline 
     @computed get content() {
         const field = Cast(this.dataDoc[this.fieldKey], VideoField);
         const interactive = Doc.GetSelectedTool() !== InkTool.None || !this.props.isSelected() ? "" : "-interactive";
@@ -569,6 +560,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
         } else {
             this.dataDoc[this.annotationKey + "-timeline"] = new List<Doc>([marker]);
         }
+        return marker;
     }
 
     // play back the video from time
@@ -628,6 +620,13 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
         return level;
     }
 
+    playLink = (doc: Doc) => {
+        const startTime = NumCast(doc.displayTimecode);
+        const endTime = NumCast(doc.undisplayTimecode, null);
+        if (startTime !== undefined) {
+            this.layoutDoc.playOnSelect && (endTime ? this.playFrom(startTime, endTime) : this.playFrom(startTime));
+        }
+    }
     // renders the markers as a document
     renderInner = computedFn(function (this: VideoBox, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), x: number, y: number, width: number, height: number, annotationKey: string) {
         const marker = observable({ view: undefined as any });
@@ -635,6 +634,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
             marker, view: <DocumentView key="view" {...OmitKeys(this.props, ["NativeWidth", "NativeHeight"]).omit} ref={action((r: DocumentView | null) => marker.view = r)}
                 Document={mark}
                 DataDoc={undefined}
+                focus={() => this.playLink(mark)}
                 PanelWidth={() => width}
                 PanelHeight={() => height}
                 renderDepth={this.props.renderDepth + 1}
@@ -703,7 +703,9 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
                         </div>;
                 })}
                 {this.selectionContainer}
-                <div className="audiobox-current" ref={this._audioRef} onClick={e => { e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc._currentTimecode) / this.videoDuration * 100}%`, pointerEvents: "none" }} />
+                <div className="audiobox-current" ref={this._audioRef} onClick={e => { e.stopPropagation(); e.preventDefault(); }}
+                    style={{ left: `${NumCast(this.layoutDoc._currentTimecode) / this.videoDuration * 100}%`, pointerEvents: "none" }}
+                />
             </div>;
     }
 
@@ -773,7 +775,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
 
     scaling = () => this.props.scaling?.() || 1;
     panelWidth = () => this.props.PanelWidth() * this.heightPercent / 100;
-    panelHeight = () => this.props.PanelHeight() * this.heightPercent / 100;
+    panelHeight = () => this.layoutDoc._fitWidth ? this.panelWidth() / Doc.NativeAspect(this.rootDoc) : this.props.PanelHeight() * this.heightPercent / 100;
     screenToLocalTransform = () => {
         const offset = (this.props.PanelWidth() - this.panelWidth()) / 2 / this.scaling();
         return this.props.ScreenToLocalTransform().translate(-offset, 0).scale(100 / this.heightPercent);
-- 
cgit v1.2.3-70-g09d2


From eba56b17b3e1f6c1cbabaafdeb4ee16421fd5a32 Mon Sep 17 00:00:00 2001
From: bobzel <zzzman@gmail.com>
Date: Mon, 25 Jan 2021 15:56:44 -0500
Subject: changed how to start/stop video when clicking/double-clicking on
 markers

---
 src/client/views/nodes/AudioBox.tsx     |  7 ++--
 src/client/views/nodes/DocumentView.tsx | 10 ++++-
 src/client/views/nodes/VideoBox.tsx     | 73 +++++++++++++++++++++------------
 3 files changed, 57 insertions(+), 33 deletions(-)

(limited to 'src/client/views/nodes/DocumentView.tsx')

diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx
index 8614200de..a481317c3 100644
--- a/src/client/views/nodes/AudioBox.tsx
+++ b/src/client/views/nodes/AudioBox.tsx
@@ -196,7 +196,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
     // play back the audio from time
     @action
     clickMarker = (anchorDoc: Doc, seekTimeInSeconds: number, endTime: number = this.audioDuration) => {
-        if (this.layoutDoc.playOnClick) return this.playOnClick(anchorDoc, seekTimeInSeconds, endTime);
+        if (this.layoutDoc.autoPlay) return this.playOnClick(anchorDoc, seekTimeInSeconds, endTime);
         this._ele && (this._ele.currentTime = this.layoutDoc._currentTimecode = seekTimeInSeconds);
         return true;
     }
@@ -262,7 +262,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         const funcs: ContextMenuProps[] = [];
         funcs.push({ description: (this.layoutDoc.playOnSelect ? "Don't play" : "Play") + " when link is selected", event: () => this.layoutDoc.playOnSelect = !this.layoutDoc.playOnSelect, icon: "expand-arrows-alt" });
         funcs.push({ description: (this.layoutDoc.hideMarkers ? "Don't hide" : "Hide") + " range markers", event: () => this.layoutDoc.hideMarkers = !this.layoutDoc.hideMarkers, icon: "expand-arrows-alt" });
-        funcs.push({ description: (this.layoutDoc.playOnClick ? "Don't play" : "Play") + " markers onClick", event: () => this.layoutDoc.playOnClick = !this.layoutDoc.playOnClick, icon: "expand-arrows-alt" });
         funcs.push({ description: (this.layoutDoc.autoPlay ? "Don't auto play" : "Auto play") + " markers onClick", event: () => this.layoutDoc.autoPlay = !this.layoutDoc.autoPlay, icon: "expand-arrows-alt" });
         ContextMenu.Instance?.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" });
     }
@@ -408,7 +407,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
         this._currMarker = m;
         this._left = left;
         this._timeline?.setPointerCapture(e.pointerId);
-        const toTimeline = (screen_delta: number, width: number) => screen_delta / width * this.audioDuration;
+        const toTimeline = (screen_delta: number, width: number) => Math.max(0, Math.min(this.audioDuration, screen_delta / width * this.audioDuration));
         setupMoveUpEvents(this, e,
             (e) => {
                 const rect = (e.target as any).getBoundingClientRect();
@@ -514,7 +513,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent<FieldViewProps, AudioD
                 parentActive={(out) => this.props.isSelected(out) || this._isChildActive}
                 whenActiveChanged={action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive))}
                 onClick={script}
-                onDoubleClick={this.layoutDoc.playOnClick ? undefined : doublescript}
+                onDoubleClick={this.layoutDoc.autoPlay ? undefined : doublescript}
                 ignoreAutoHeight={false}
                 bringToFront={emptyFunction}
                 scriptContext={this} />
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 6620614f8..7b1b1bf0c 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -382,9 +382,11 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                             scriptContext: this.props.scriptContext,
                             thisContainer: this.props.ContainingCollectionDoc,
                             documentView: this.props.DocumentView,
+                            clientX: e.clientX,
+                            clientY: e.clientY,
                             shiftKey: e.shiftKey
                         }, console.log);
-                        undoBatch(func)();
+                        UndoManager.RunInBatch(() => func().result?.select === true ? this.props.select(false) : "", "on double click");
                     } else if (!Doc.IsSystem(this.props.Document)) {
                         if (this.props.Document.type !== DocumentType.LABEL) {
                             UndoManager.RunInBatch(() => {
@@ -398,19 +400,23 @@ export class DocumentViewInternal extends DocComponent<DocumentViewInternalProps
                 }
             } else if (this.onClickHandler?.script && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) { // bcz: hack? don't execute script if you're clicking on a scripting box itself
                 const shiftKey = e.shiftKey;
+                const clientX = e.clientX;
+                const clientY = e.clientY;
                 const func = () => this.onClickHandler.script.run({
                     this: this.layoutDoc,
                     self: this.rootDoc,
                     scriptContext: this.props.scriptContext,
                     thisContainer: this.props.ContainingCollectionDoc,
                     documentView: this.props.DocumentView,
+                    clientX: clientX,
+                    clientY: clientY,
                     shiftKey
                 }, console.log);
                 const clickFunc = () => {
                     if (!Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-undo"] as Doc) &&
                         !Doc.AreProtosEqual(this.props.Document, Doc.UserDoc()["dockedBtn-redo"] as Doc) &&
                         !this.onClickHandler.script.originalScript.includes("selectMainMenu")) {
-                        UndoManager.RunInBatch(() => func().result === true ? this.props.select(false) : "", "on click");
+                        UndoManager.RunInBatch(() => func().result?.select === true ? this.props.select(false) : "", "on click");
                     } else func();
                 };
                 if (this.onDoubleClickHandler) {
diff --git a/src/client/views/nodes/VideoBox.tsx b/src/client/views/nodes/VideoBox.tsx
index 6ca4a589a..fe76af55e 100644
--- a/src/client/views/nodes/VideoBox.tsx
+++ b/src/client/views/nodes/VideoBox.tsx
@@ -91,10 +91,10 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
         VideoBox.Instance = this;
 
         // onClick play scripts
-        VideoBox.RangeScript = VideoBox.RangeScript || ScriptField.MakeFunction(`scriptContext.clickMarker(self, this.displayTimecode, this.undisplayTimecode)`, { self: Doc.name, scriptContext: "any" })!;
-        VideoBox.LabelScript = VideoBox.LabelScript || ScriptField.MakeFunction(`scriptContext.clickMarker(self, this.displayTimecode)`, { self: Doc.name, scriptContext: "any" })!;
-        VideoBox.RangePlayScript = VideoBox.RangePlayScript || ScriptField.MakeFunction(`scriptContext.playOnClick(self, this.displayTimecode, this.undisplayTimecode)`, { self: Doc.name, scriptContext: "any" })!;
-        VideoBox.LabelPlayScript = VideoBox.LabelPlayScript || ScriptField.MakeFunction(`scriptContext.playOnClick(self, this.displayTimecode)`, { self: Doc.name, scriptContext: "any" })!;
+        VideoBox.RangeScript = VideoBox.RangeScript || ScriptField.MakeFunction(`scriptContext.clickMarker(self, clientX, this.displayTimecode, this.undisplayTimecode)`, { self: Doc.name, clientX: "number", scriptContext: "any" })!;
+        VideoBox.LabelScript = VideoBox.LabelScript || ScriptField.MakeFunction(`scriptContext.clickMarker(self, clientX, this.displayTimecode)`, { self: Doc.name, clientX: "number", scriptContext: "any" })!;
+        VideoBox.RangePlayScript = VideoBox.RangePlayScript || ScriptField.MakeFunction(`scriptContext.playOnClick(self, clientX, this.displayTimecode, this.undisplayTimecode)`, { self: Doc.name, clientX: "number", scriptContext: "any" })!;
+        VideoBox.LabelPlayScript = VideoBox.LabelPlayScript || ScriptField.MakeFunction(`scriptContext.playOnClick(self, clientX, this.displayTimecode)`, { self: Doc.name, clientX: "number", scriptContext: "any" })!;
     }
 
     getAnchor = () => {
@@ -320,8 +320,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
                     this._videoRef!.srcObject = !this._screenCapture ? undefined : await (navigator.mediaDevices as any).getDisplayMedia({ video: true });
                 }), icon: "expand-arrows-alt"
             });
-            subitems.push({ description: (this.layoutDoc.playOnClick ? "Don't play" : "Play") + " markers onClick", event: () => this.layoutDoc.playOnClick = !this.layoutDoc.playOnClick, icon: "expand-arrows-alt" });
-            subitems.push({ description: (this.layoutDoc.playOnClick ? "Don't auto play" : "Auto play") + " markers onClick", event: () => this.layoutDoc.autoPlay = !this.layoutDoc.autoPlay, icon: "expand-arrows-alt" });
+            subitems.push({ description: (this.layoutDoc.autoPlay ? "Don't auto play" : "Auto play") + " markers onClick", event: () => this.layoutDoc.autoPlay = !this.layoutDoc.autoPlay, icon: "expand-arrows-alt" });
             ContextMenu.Instance.addItem({ description: "Options...", subitems: subitems, icon: "video" });
         }
     }
@@ -515,20 +514,18 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
     onPointerDownTimeline = (e: React.PointerEvent): void => {
         const rect = this._timeline?.getBoundingClientRect();// (e.target as any).getBoundingClientRect();
         if (rect && e.target !== this._audioRef.current && this.active()) {
-            const wasPaused = !this._playing;
-            this.player!.currentTime = this.layoutDoc._currentTimecode = (e.clientX - rect.x) / rect.width * this.videoDuration;
-            wasPaused && this.Pause();
+            const wasPlaying = this._playing;
+            if (this._playing) this.Pause();
 
-            const toTimeline = (screen_delta: number) => screen_delta / rect.width * this.videoDuration;
-            this._markerStart = this._markerEnd = toTimeline(e.clientX - rect.x);
+            this._markerStart = this._markerEnd = this.toTimeline(e.clientX - rect.x, rect.width);
             VideoBox.SelectingRegion = this;
             setupMoveUpEvents(this, e,
                 action(e => {
-                    this._markerEnd = toTimeline(e.clientX - rect.x);
+                    this._markerEnd = this.toTimeline(e.clientX - rect.x, rect.width);
                     return false;
                 }),
                 action((e, movement) => {
-                    this._markerEnd = toTimeline(e.clientX - rect.x);
+                    this._markerEnd = this.toTimeline(e.clientX - rect.x, rect.width);
                     if (this._markerEnd < this._markerStart) {
                         const tmp = this._markerStart;
                         this._markerStart = this._markerEnd;
@@ -537,9 +534,11 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
                     VideoBox.SelectingRegion === this && (Math.abs(movement[0]) > 15) && this.createMarker(this._markerStart, this._markerEnd);
                     VideoBox.SelectingRegion = undefined;
                 }),
-                e => {
+                (e, doubleTap) => {
                     this.props.select(false);
                     e.shiftKey && this.createMarker(this.player!.currentTime);
+                    !wasPlaying && (this.player!.currentTime = this.layoutDoc._currentTimecode = (e.clientX - rect.x) / rect.width * this.videoDuration);
+                    !wasPlaying && doubleTap && this.Play();
                 }
                 , this.props.isSelected(true) || this._isChildActive);
         }
@@ -563,36 +562,56 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
         return marker;
     }
 
-    // play back the video from time
     @action
-    playOnClick = (anchorDoc: Doc, seekTimeInSeconds: number, endTime: number = this.videoDuration) => {
-        this.playFrom(seekTimeInSeconds, endTime);
-        return true; // select
+    playOnClick = (anchorDoc: Doc, clientX: number, seekTimeInSeconds: number, endTime: number = this.videoDuration) => {
+        if (this.layoutDoc.autoPlay) {
+            if (this._playing) this.Pause();
+            else this.playFrom(seekTimeInSeconds, endTime);
+        } else {
+            if (seekTimeInSeconds < NumCast(this.layoutDoc._currentTimecode) && endTime > NumCast(this.layoutDoc._currentTimecode)) {
+                if (!this.layoutDoc.autoPlay && this._playing) {
+                    this.Pause();
+                } else {
+                    this.Play();
+                }
+            } else {
+                this.playFrom(seekTimeInSeconds, endTime);
+            }
+        }
+        return { select: true };
     }
 
-    // play back the video from time
     @action
-    clickMarker = (anchorDoc: Doc, seekTimeInSeconds: number, endTime: number = this.videoDuration) => {
-        if (this.layoutDoc.playOnClick) return this.playOnClick(anchorDoc, seekTimeInSeconds, endTime);
-        this.player && (this.player.currentTime = this.layoutDoc._currentTimecode = seekTimeInSeconds);
-        return true; // select
+    clickMarker = (anchorDoc: Doc, clientX: number, seekTimeInSeconds: number, endTime: number = this.videoDuration) => {
+        if (seekTimeInSeconds < NumCast(this.layoutDoc._currentTimecode) + 1e-4 && endTime > NumCast(this.layoutDoc._currentTimecode) - 1e-4) {
+            if (this._playing) this.Pause();
+            else if (this.layoutDoc.autoPlay) this.Play();
+            else if (!this.layoutDoc.autoPlay) {
+                const rect = this._timeline?.getBoundingClientRect();
+                rect && this.Seek(this.toTimeline(clientX - rect.x, rect.width));
+            }
+        } else {
+            if (this.layoutDoc.autoPlay) this.playFrom(seekTimeInSeconds, endTime);
+            else this.Seek(seekTimeInSeconds);
+        }
+        return { select: true };
     }
 
+    toTimeline = (screen_delta: number, width: number) => Math.max(0, Math.min(this.videoDuration, screen_delta / width * this.videoDuration));
     // starting the drag event for marker resizing
     onPointerDown = (e: React.PointerEvent, m: any, left: boolean): void => {
         this._currMarker = m;
         this._left = left;
         this._timeline?.setPointerCapture(e.pointerId);
-        const toTimeline = (screen_delta: number, width: number) => screen_delta / width * this.videoDuration;
         setupMoveUpEvents(this, e,
             (e: PointerEvent) => {
                 const rect = (e.target as any).getBoundingClientRect();
-                this.changeMarker(this._currMarker, toTimeline(e.clientX - rect.x, rect.width));
+                this.changeMarker(this._currMarker, this.toTimeline(e.clientX - rect.x, rect.width));
                 return false;
             },
             (e: PointerEvent) => {
                 const rect = (e.target as any).getBoundingClientRect();
-                this.player!.currentTime = this.layoutDoc._currentTimecode = toTimeline(e.clientX - rect.x, rect.width);
+                this.player!.currentTime = this.layoutDoc._currentTimecode = this.toTimeline(e.clientX - rect.x, rect.width);
                 this._timeline?.releasePointerCapture(e.pointerId);
             },
             emptyFunction);
@@ -647,7 +666,7 @@ export class VideoBox extends ViewBoxAnnotatableComponent<FieldViewProps, VideoD
                 parentActive={(out) => this.props.isSelected(out) || this._isChildActive}
                 whenActiveChanged={action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive))}
                 onClick={script}
-                onDoubleClick={this.layoutDoc.playOnClick ? undefined : doublescript}
+                onDoubleClick={doublescript}
                 ignoreAutoHeight={false}
                 bringToFront={emptyFunction}
                 scriptContext={this} />
-- 
cgit v1.2.3-70-g09d2

