From 264292f75d17c19e65bc4707b10a713b64510cf1 Mon Sep 17 00:00:00 2001 From: yunahi <60233430+yunahi@users.noreply.github.com> Date: Thu, 1 Oct 2020 18:41:45 +0900 Subject: fixed resize/rotate --- src/client/views/DocumentDecorations.tsx | 9 ++++--- src/client/views/InkStrokeProperties.ts | 46 +++++++++++++++++++++----------- src/client/views/InkingStroke.tsx | 1 + 3 files changed, 37 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 9432d1ffb..dfcb6cda9 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -290,10 +290,11 @@ export class DocumentDecorations extends React.Component<{}, { value: string }> const right = Math.max(...xs); const bottom = Math.max(...ys); - // doc._height = (bottom - top) * element.props.ScreenToLocalTransform().Scale; - // doc._width = (right - left) * element.props.ScreenToLocalTransform().Scale; - doc._height = (bottom - top); - doc._width = (right - left); + doc._height = (bottom - top) * element.props.ScreenToLocalTransform().Scale; + doc._width = (right - left) * element.props.ScreenToLocalTransform().Scale; + // doc._height = (bottom - top); + // doc._width = (right - left); + } index++; diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index ad5c70fb1..b04ac8610 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -7,6 +7,8 @@ import { Cast, NumCast } from "../../fields/Types"; import { DocumentType } from "../documents/DocumentTypes"; import { SelectionManager } from "../util/SelectionManager"; import { undoBatch } from "../util/UndoManager"; +import { DocumentView } from "./nodes/DocumentView"; +import { returnVal } from "../../Utils"; export class InkStrokeProperties { static Instance: InkStrokeProperties | undefined; @@ -14,6 +16,7 @@ export class InkStrokeProperties { private _lastFill = "#D0021B"; private _lastLine = "#D0021B"; private _lastDash = "2"; + private _inkDocs: { x: number, y: number, width: number, height: number }[] = []; @observable _lock = false; @observable _controlBtn = false; @@ -190,12 +193,20 @@ export class InkStrokeProperties { doc._height = (bottom - top); doc._width = (right - left); + } index++; } })); } + @undoBatch + @action + resetPoints = () => { + + } + + @undoBatch @action control = (xDiff: number, yDiff: number, controlNum: number) => { @@ -218,31 +229,36 @@ export class InkStrokeProperties { (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 2) || ((ink[0].X === ink[ink.length - 1].X) && (ink[0].Y === ink[ink.length - 1].Y) && (i === 0 || i === ink.length - 1) && (controlNum === 0 || controlNum === ink.length - 1)) ) { - newPoints.push({ X: ink[i].X - (xDiff * inkView.props.ScreenToLocalTransform().Scale), Y: ink[i].Y - (yDiff * inkView.props.ScreenToLocalTransform().Scale) }); + newPoints.push({ X: ink[i].X - (xDiff), Y: ink[i].Y - (yDiff) }); } else { newPoints.push({ X: ink[i].X, Y: ink[i].Y }); } } + const oldHeight = doc._height; + const oldWidth = doc._width; const oldx = doc.x; const oldy = doc.y; - const xs = ink.map(p => p.X); - const ys = ink.map(p => p.Y); - const left = Math.min(...xs); - const top = Math.min(...ys); + const oldxs = ink.map(p => p.X); + const oldys = ink.map(p => p.Y); + const oldleft = Math.min(...oldxs); + const oldtop = Math.min(...oldys); + const oldright = Math.max(...oldxs); + const oldbottom = Math.max(...oldys); Doc.GetProto(doc).data = new InkField(newPoints); - const xs2 = newPoints.map(p => p.X); - const ys2 = newPoints.map(p => p.Y); - const left2 = Math.min(...xs2); - const top2 = Math.min(...ys2); - const right2 = Math.max(...xs2); - const bottom2 = Math.max(...ys2); - doc._height = (bottom2 - top2); - doc._width = (right2 - left2); + const newxs = newPoints.map(p => p.X); + const newys = newPoints.map(p => p.Y); + const newleft = Math.min(...newxs); + const newtop = Math.min(...newys); + const newright = Math.max(...newxs); + const newbottom = Math.max(...newys); + //if points move out of bounds + doc._height = (newbottom - newtop) * inkView.props.ScreenToLocalTransform().Scale; + doc._width = (newright - newleft) * inkView.props.ScreenToLocalTransform().Scale; - doc.x = oldx - (left - left2); - doc.y = oldy - (top - top2); + doc.x = oldx - (oldleft - newleft) * inkView.props.ScreenToLocalTransform().Scale; + doc.y = oldy - (oldtop - newtop) * inkView.props.ScreenToLocalTransform().Scale; } } diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 186406424..2a7d4a5ad 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -48,6 +48,7 @@ export class InkingStroke extends ViewBoxBaseComponent { //TODO:renew points before controlling + InkStrokeProperties.Instance?.control(0.001, 0.001, 1); setupMoveUpEvents(this, e, this.onControlMove, this.onControlup, (e) => { }); this._controlUndo = UndoManager.StartBatch("DocDecs set radius"); this._prevX = e.clientX; -- cgit v1.2.3-70-g09d2 From 768ab508529ab2b7f43a44592e5dc2c9f15a68a5 Mon Sep 17 00:00:00 2001 From: yunahi <60233430+yunahi@users.noreply.github.com> Date: Sat, 9 Jan 2021 01:31:43 +0900 Subject: spotlight --- src/client/views/collections/TabDocView.tsx | 10 ++++++++ src/client/views/nodes/PresBox.tsx | 37 ++++++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 530595cd0..b3ad0f82e 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -142,6 +142,16 @@ export class TabDocView extends React.Component { pinDoc.presStartTime = 0; pinDoc.presEndTime = doc.duration; } + //save position + if (pinDoc.isInkMask) { + pinDoc.y = doc.y; + pinDoc.x = doc.x; + pinDoc.presHideAfter = true; + pinDoc.presHideBefore = true; + pinDoc.title = doc.title + "- Spotlight"; + pinDoc.presMovement = PresMovement.None; + + } if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true; const dview = CollectionDockingView.Instance.props.Document; const fieldKey = CollectionDockingView.Instance.props.fieldKey; diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 683cb938a..56b4bb688 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -357,8 +357,8 @@ export class PresBox extends ViewBoxBaseComponent } else if (curDoc.presMovement === PresMovement.Pan && targetDoc) { await DocumentManager.Instance.jumpToDocument(targetDoc, false, openInTab, srcContext, undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection); // documents open in new tab instead of on right } else if ((curDoc.presMovement === PresMovement.Zoom || curDoc.presMovement === PresMovement.Jump) && targetDoc) { - //awaiting jump so that new scale can be found, since jumping is async - await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext, undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection); // documents open in new tab instead of on right + //awaiting jump so that new scale can be found, since jumping is async + await DocumentManager.Instance.jumpToDocument(targetDoc, true, openInTab, srcContext, undefined, undefined, undefined, includesDoc || tab ? undefined : resetSelection); // documents open in new tab instead of on right } // After navigating to the document, if it is added as a presPinView then it will // adjust the pan and scale to that of the pinView when it was added. @@ -367,6 +367,7 @@ export class PresBox extends ViewBoxBaseComponent this.navigateToView(targetDoc, activeItem); } // TODO: Add progressivize for navigating web (storing websites for given frames) + } /** @@ -470,6 +471,7 @@ export class PresBox extends ViewBoxBaseComponent this.next(); } } + await timer(duration); this.next(); // then the created Promise can be awaited if (i === this.childDocs.length - 1) { setTimeout(() => { @@ -673,11 +675,40 @@ export class PresBox extends ViewBoxBaseComponent //Regular click @action - selectElement = (doc: Doc) => { + selectElement = async (doc: Doc) => { const context = Cast(doc.context, Doc, null); this.gotoDocument(this.childDocs.indexOf(doc)); if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(context), 0); else this.updateCurrentPresentation(context); + + + + if (this.targetDoc.isInkMask) { + if (this.activeItem.y !== undefined && + this.activeItem.x !== undefined && + this.targetDoc.y !== undefined && + this.targetDoc.y !== undefined) { + const timer = (ms: number) => new Promise(res => this._presTimer = setTimeout(res, ms)); + + const ydiff = this.activeItem.y - this.targetDoc.y; + const xdiff = this.activeItem.x - this.targetDoc.x; + + const time = 10; + + const yOffset = ydiff / time; + const xOffset = xdiff / time; + + for (let i = 0; i < time; i++) { + const newy = Number(this.targetDoc.y) + yOffset; + const newx = Number(this.targetDoc.x) + xOffset; + this.targetDoc.y = newy; + this.targetDoc.x = newx; + await timer(0.1); + } + + } + + } } //Command click -- cgit v1.2.3-70-g09d2 From ff7df91f8502e3753e28d742ef8b5dd2ff33c801 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 11 Jan 2021 13:09:55 -0500 Subject: adjustments to restore inkMask functionality --- src/client/views/DocumentDecorations.tsx | 3 ++- src/client/views/InkingStroke.tsx | 1 - src/client/views/StyleProvider.tsx | 2 +- src/client/views/nodes/DocumentView.tsx | 6 ++++-- 4 files changed, 7 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 497c66d98..a24db53c2 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -559,7 +559,8 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b const canDelete = SelectionManager.Views().some(docView => { const collectionAcl = docView.props.ContainingCollectionView ? GetEffectiveAcl(docView.props.ContainingCollectionDoc?.[DataSym]) : AclEdit; const docAcl = GetEffectiveAcl(docView.props.Document); - return !docView.props.Document._stayInCollection && (collectionAcl === AclAdmin || collectionAcl === AclEdit || docAcl === AclAdmin); + return (!docView.props.Document._stayInCollection || docView.props.Document.isInkMask) && + (collectionAcl === AclAdmin || collectionAcl === AclEdit || docAcl === AclAdmin); }); const canOpen = SelectionManager.Views().some(docView => !docView.props.Document._stayInCollection); const closeIcon = !canDelete ? (null) : ( diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 8ed6fbd85..dbe2d73d1 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -35,7 +35,6 @@ export class InkingStroke extends ViewBoxBaseComponent { - this.props.Document._backgroundColor = "rgba(0,0,0,0.7)"; this.props.Document.mixBlendMode = "hard-light"; this.props.Document.color = "#9b9b9bff"; //this.props.Document._stayInCollection = true; diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index e1600f748..5a3abba2d 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -106,7 +106,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt boolean; export type DocFocusFunc = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc, dontCenter?: boolean, focused?: boolean) => void; @@ -965,9 +966,10 @@ export class DocumentView extends React.Component { {!this.props.Document || !this.props.PanelWidth() ? (null) : (
0.001 ? `${100 * (this.props.PanelWidth() - this.Xshift * 2) / this.props.PanelWidth()}%` : this.props.PanelWidth(), - height: Math.abs(this.YShift) > 0.001 ? this.props.Document._fitWidth ? `${this.panelHeight}px` : `${100 * this.nativeHeight / this.nativeWidth * this.props.PanelWidth() / this.props.PanelHeight()}%` : this.props.PanelHeight(), + width: this.props.Document.isInkMask ? InkingStroke.MaskDim : Math.abs(this.Xshift) > 0.001 ? `${100 * (this.props.PanelWidth() - this.Xshift * 2) / this.props.PanelWidth()}%` : this.props.PanelWidth(), + height: this.props.Document.isInkMask ? InkingStroke.MaskDim : Math.abs(this.YShift) > 0.001 ? this.props.Document._fitWidth ? `${this.panelHeight}px` : `${100 * this.nativeHeight / this.nativeWidth * this.props.PanelWidth() / this.props.PanelHeight()}%` : this.props.PanelHeight(), }}> this.docView = r)} />
)} -- cgit v1.2.3-70-g09d2 From 7a1af910d1c4804cdc702000f8a278f5dd13999b Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 11 Jan 2021 13:21:48 -0500 Subject: cleanup of ink stroke changes --- src/client/views/DocumentDecorations.tsx | 8 ++++---- src/client/views/InkStrokeProperties.ts | 34 +++++++++++--------------------- 2 files changed, 16 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 2f4126a1e..744683a0f 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -271,10 +271,10 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b const right = Math.max(...xs); const bottom = Math.max(...ys); - doc._height = (bottom - top) * element.props.ScreenToLocalTransform().Scale; - doc._width = (right - left) * element.props.ScreenToLocalTransform().Scale; - // doc._height = (bottom - top); - // doc._width = (right - left); + // doc._height = (bottom - top) * element.props.ScreenToLocalTransform().Scale; + // doc._width = (right - left) * element.props.ScreenToLocalTransform().Scale; + doc._height = (bottom - top); + doc._width = (right - left); } diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index df0f354cd..73591c6a6 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -7,8 +7,6 @@ import { Cast, NumCast } from "../../fields/Types"; import { DocumentType } from "../documents/DocumentTypes"; import { SelectionManager } from "../util/SelectionManager"; import { undoBatch } from "../util/UndoManager"; -import { DocumentView } from "./nodes/DocumentView"; -import { returnVal } from "../../Utils"; export class InkStrokeProperties { static Instance: InkStrokeProperties | undefined; @@ -216,35 +214,28 @@ export class InkStrokeProperties { if (doc.type === DocumentType.INK && doc.x && doc.y && doc._width && doc._height && doc.data) { const ink = Cast(doc.data, InkField)?.inkData; if (ink) { - const newPoints: { X: number, Y: number }[] = []; const order = controlNum % 4; for (var i = 0; i < ink.length; i++) { - if (controlNum === i || - (order === 0 && i === controlNum + 1) || - (order === 0 && controlNum !== 0 && i === controlNum - 2) || - (order === 0 && controlNum !== 0 && i === controlNum - 1) || - (order === 3 && i === controlNum - 1) || - (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 1) || - (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 2) - || ((ink[0].X === ink[ink.length - 1].X) && (ink[0].Y === ink[ink.length - 1].Y) && (i === 0 || i === ink.length - 1) && (controlNum === 0 || controlNum === ink.length - 1)) - ) { - newPoints.push({ X: ink[i].X - (xDiff), Y: ink[i].Y - (yDiff) }); - } - else { - newPoints.push({ X: ink[i].X, Y: ink[i].Y }); - } + newPoints.push( + (controlNum === i || + (order === 0 && i === controlNum + 1) || + (order === 0 && controlNum !== 0 && i === controlNum - 2) || + (order === 0 && controlNum !== 0 && i === controlNum - 1) || + (order === 3 && i === controlNum - 1) || + (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 1) || + (order === 3 && controlNum !== ink.length - 1 && i === controlNum + 2) || + ((ink[0].X === ink[ink.length - 1].X) && (ink[0].Y === ink[ink.length - 1].Y) && (i === 0 || i === ink.length - 1) && (controlNum === 0 || controlNum === ink.length - 1)) + ) ? + { X: ink[i].X - xDiff, Y: ink[i].Y - yDiff } : + { X: ink[i].X, Y: ink[i].Y }) } - const oldHeight = doc._height; - const oldWidth = doc._width; const oldx = doc.x; const oldy = doc.y; const oldxs = ink.map(p => p.X); const oldys = ink.map(p => p.Y); const oldleft = Math.min(...oldxs); const oldtop = Math.min(...oldys); - const oldright = Math.max(...oldxs); - const oldbottom = Math.max(...oldys); Doc.GetProto(doc).data = new InkField(newPoints); const newxs = newPoints.map(p => p.X); const newys = newPoints.map(p => p.Y); @@ -259,7 +250,6 @@ export class InkStrokeProperties { doc.x = oldx - (oldleft - newleft) * inkView.props.ScreenToLocalTransform().Scale; doc.y = oldy - (oldtop - newtop) * inkView.props.ScreenToLocalTransform().Scale; - } } } -- cgit v1.2.3-70-g09d2 From a8545c5f31200d2d58696223c5050cbf9cf553ae Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 11 Jan 2021 13:35:56 -0500 Subject: from last --- src/client/views/InkStrokeProperties.ts | 8 -------- src/client/views/nodes/PresBox.tsx | 19 ++++--------------- 2 files changed, 4 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index 73591c6a6..fcc6b9da0 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -191,20 +191,12 @@ export class InkStrokeProperties { doc._height = (bottom - top); doc._width = (right - left); - } index++; } })); } - @undoBatch - @action - resetPoints = () => { - - } - - @undoBatch @action control = (xDiff: number, yDiff: number, controlNum: number) => { diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index fb3598a04..271a7274f 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -774,33 +774,22 @@ export class PresBox extends ViewBoxBaseComponent if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(context), 0); else this.updateCurrentPresentation(context); - - if (this.targetDoc.isInkMask) { if (this.activeItem.y !== undefined && this.activeItem.x !== undefined && this.targetDoc.y !== undefined && this.targetDoc.y !== undefined) { const timer = (ms: number) => new Promise(res => this._presTimer = setTimeout(res, ms)); - - const ydiff = this.activeItem.y - this.targetDoc.y; - const xdiff = this.activeItem.x - this.targetDoc.x; - const time = 10; - - const yOffset = ydiff / time; - const xOffset = xdiff / time; + const ydiff = NumCast(this.activeItem.y) - NumCast(this.targetDoc.y); + const xdiff = NumCast(this.activeItem.x) - NumCast(this.targetDoc.x); for (let i = 0; i < time; i++) { - const newy = Number(this.targetDoc.y) + yOffset; - const newx = Number(this.targetDoc.x) + xOffset; - this.targetDoc.y = newy; - this.targetDoc.x = newx; + this.targetDoc.x = NumCast(this.targetDoc.x) + xdiff / time; + this.targetDoc.y = NumCast(this.targetDoc.y) + ydiff / time; await timer(0.1); } - } - } } -- cgit v1.2.3-70-g09d2 From b239f049578edeefc5971f3e682e3e70e2e76132 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 11 Jan 2021 13:37:54 -0500 Subject: from last --- src/client/views/DocumentDecorations.tsx | 2 -- src/client/views/nodes/PresBox.tsx | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 744683a0f..d7b0b5158 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -275,8 +275,6 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b // doc._width = (right - left) * element.props.ScreenToLocalTransform().Scale; doc._height = (bottom - top); doc._width = (right - left); - - } index++; } diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 271a7274f..90897b8fd 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -777,7 +777,7 @@ export class PresBox extends ViewBoxBaseComponent if (this.targetDoc.isInkMask) { if (this.activeItem.y !== undefined && this.activeItem.x !== undefined && - this.targetDoc.y !== undefined && + this.targetDoc.x !== undefined && this.targetDoc.y !== undefined) { const timer = (ms: number) => new Promise(res => this._presTimer = setTimeout(res, ms)); const time = 10; -- cgit v1.2.3-70-g09d2 From 761596b7bb7b4cab18e1e1df62330a3a11a7af03 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 11 Jan 2021 13:57:14 -0500 Subject: generalized spotlight moving to be available by any document --- src/client/views/DocumentButtonBar.tsx | 11 +++---- src/client/views/collections/CollectionMenu.tsx | 4 +-- src/client/views/collections/TabDocView.tsx | 12 ++++---- src/client/views/nodes/PresBox.tsx | 39 ++++++++++++++----------- src/mobile/MobileInterface.tsx | 2 +- 5 files changed, 37 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 96f5d78fd..3eabb294d 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -186,20 +186,21 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV @computed get pinButton() { const targetDoc = this.view0?.props.Document; - const isPinned = targetDoc && Doc.isDocPinned(targetDoc); - return !targetDoc ? (null) :
{SelectionManager.Views().length > 1 ? "Pin multiple documents to presentation" : "Pin to presentation"}
}> + return !targetDoc ? (null) : {SelectionManager.Views().length > 1 ? "Pin multiple documents to presentation" : "Pin to presentation"}}>
this.props.views().map(view => view && TabDocView.PinDoc(view.props.Document, false)))}> + onClick={undoBatch(e => this.props.views().map(view => view && TabDocView.PinDoc(view.props.Document /*, { setPosition: true }*/)))}> -
; + +
; } @undoBatch @action pinWithView = (targetDoc: Doc) => { if (targetDoc) { - TabDocView.PinDoc(targetDoc, false); + TabDocView.PinDoc(targetDoc); const activeDoc = PresBox.Instance.childDocs[PresBox.Instance.childDocs.length - 1]; const scrollable: boolean = (targetDoc.type === DocumentType.PDF || targetDoc.type === DocumentType.RTF || targetDoc.type === DocumentType.WEB || targetDoc._viewType === CollectionViewType.Stacking); const pannable: boolean = ((targetDoc.type === DocumentType.COL && targetDoc._viewType === CollectionViewType.Freeform) || targetDoc.type === DocumentType.IMG); diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx index 85fcf6384..5670d45f5 100644 --- a/src/client/views/collections/CollectionMenu.tsx +++ b/src/client/views/collections/CollectionMenu.tsx @@ -389,7 +389,7 @@ export class CollectionViewBaseChrome extends React.Component{Doc.isDocPinned(targetDoc) ? "Unpin from presentation" : "Pin to presentation"}} placement="top"> ; @@ -399,7 +399,7 @@ export class CollectionViewBaseChrome extends React.Component) => { if (targetDoc) { - TabDocView.PinDoc(targetDoc, false); + TabDocView.PinDoc(targetDoc); const presArray: Doc[] = PresBox.Instance?.sortArray(); const size: number = PresBox.Instance?._selectedArray.size; const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined; diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 9a0759fe5..09f709a5e 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -24,7 +24,7 @@ import { Transform } from '../../util/Transform'; import { undoBatch, UndoManager } from "../../util/UndoManager"; import { DocumentView, DocAfterFocusFunc, DocumentViewProps } from "../nodes/DocumentView"; import { FieldViewProps } from '../nodes/FieldView'; -import { PresBox, PresMovement } from '../nodes/PresBox'; +import { PresBox, PresMovement, PinProps } from '../nodes/PresBox'; import { DefaultLayerProvider, DefaultStyleProvider, StyleLayers, StyleProp } from '../StyleProvider'; import { CollectionDockingView } from './CollectionDockingView'; import { CollectionDockingViewMenu } from './CollectionDockingViewMenu'; @@ -166,8 +166,8 @@ export class TabDocView extends React.Component { * Adds a document to the presentation view **/ @action - public static async PinDoc(doc: Doc, unpin = false, audioRange?: boolean) { - if (unpin) console.log('TODO: Remove UNPIN from this location'); + public static async PinDoc(doc: Doc, pinProps?: PinProps) { + if (pinProps?.unpin) console.log('TODO: Remove UNPIN from this location'); //add this new doc to props.Document const curPres = CurrentUserUtils.ActivePresentation; if (curPres) { @@ -183,21 +183,21 @@ export class TabDocView extends React.Component { const size: number = PresBox.Instance?._selectedArray.size; const presSelected: Doc | undefined = presArray && size ? presArray[size - 1] : undefined; Doc.AddDocToList(curPres, "data", pinDoc, presSelected); - if (!audioRange && (pinDoc.type === DocumentType.AUDIO || pinDoc.type === DocumentType.VID)) { + if (!pinProps?.audioRange && (pinDoc.type === DocumentType.AUDIO || pinDoc.type === DocumentType.VID)) { pinDoc.mediaStart = "manual"; pinDoc.mediaStop = "manual"; pinDoc.presStartTime = 0; pinDoc.presEndTime = pinDoc.type === DocumentType.AUDIO ? doc.duration : NumCast(doc["data-duration"]); } //save position - if (pinDoc.isInkMask) { + if (pinProps?.setPosition || pinDoc.isInkMask) { + pinDoc.setPosition = true; pinDoc.y = doc.y; pinDoc.x = doc.x; pinDoc.presHideAfter = true; pinDoc.presHideBefore = true; pinDoc.title = doc.title + "- Spotlight"; pinDoc.presMovement = PresMovement.None; - } if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true; const dview = CollectionDockingView.Instance.props.Document; diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 90897b8fd..aef776563 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -66,6 +66,12 @@ export enum PresColor { SlideBackground = "#d5dce2", } +export class PinProps { + audioRange?: boolean; + unpin?: boolean; + setPosition?: boolean; +} + type PresBoxSchema = makeInterface<[typeof documentSchema]>; const PresBoxDocument = makeInterface(documentSchema); @@ -711,7 +717,7 @@ export class PresBox extends ViewBoxBaseComponent audio.presStartTime = NumCast(doc.audioStart); audio.presEndTime = NumCast(doc.audioEnd); audio.presDuration = NumCast(doc.audioEnd) - NumCast(doc.audioStart); - TabDocView.PinDoc(audio, false, true); + TabDocView.PinDoc(audio, { audioRange: true }); setTimeout(() => this.removeDocument(doc), 0); return false; } @@ -774,21 +780,20 @@ export class PresBox extends ViewBoxBaseComponent if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(context), 0); else this.updateCurrentPresentation(context); - if (this.targetDoc.isInkMask) { - if (this.activeItem.y !== undefined && - this.activeItem.x !== undefined && - this.targetDoc.x !== undefined && - this.targetDoc.y !== undefined) { - const timer = (ms: number) => new Promise(res => this._presTimer = setTimeout(res, ms)); - const time = 10; - const ydiff = NumCast(this.activeItem.y) - NumCast(this.targetDoc.y); - const xdiff = NumCast(this.activeItem.x) - NumCast(this.targetDoc.x); - - for (let i = 0; i < time; i++) { - this.targetDoc.x = NumCast(this.targetDoc.x) + xdiff / time; - this.targetDoc.y = NumCast(this.targetDoc.y) + ydiff / time; - await timer(0.1); - } + if (this.activeItem.setPosition && + this.activeItem.y !== undefined && + this.activeItem.x !== undefined && + this.targetDoc.x !== undefined && + this.targetDoc.y !== undefined) { + const timer = (ms: number) => new Promise(res => this._presTimer = setTimeout(res, ms)); + const time = 10; + const ydiff = NumCast(this.activeItem.y) - NumCast(this.targetDoc.y); + const xdiff = NumCast(this.activeItem.x) - NumCast(this.targetDoc.x); + + for (let i = 0; i < time; i++) { + this.targetDoc.x = NumCast(this.targetDoc.x) + xdiff / time; + this.targetDoc.y = NumCast(this.targetDoc.y) + ydiff / time; + await timer(0.1); } } } @@ -1731,7 +1736,7 @@ export class PresBox extends ViewBoxBaseComponent const presData = Cast(this.rootDoc.data, listSpec(Doc)); if (data && presData) { data.push(doc); - TabDocView.PinDoc(doc, false); + TabDocView.PinDoc(doc); this.gotoDocument(this.childDocs.length, this.activeItem); } else { this.props.addDocTab(doc, "add:right"); diff --git a/src/mobile/MobileInterface.tsx b/src/mobile/MobileInterface.tsx index c4a6433c8..c7e2d02cb 100644 --- a/src/mobile/MobileInterface.tsx +++ b/src/mobile/MobileInterface.tsx @@ -512,7 +512,7 @@ export class MobileInterface extends React.Component { return
TabDocView.PinDoc(this._activeDoc, isPinned)}> + onClick={e => TabDocView.PinDoc(this._activeDoc, { unpin: isPinned })}>
; } else return (null); -- cgit v1.2.3-70-g09d2 From a134dab9a458efcc8b4bd60489483e68f9332397 Mon Sep 17 00:00:00 2001 From: bobzel Date: Tue, 12 Jan 2021 17:50:25 -0500 Subject: fixed layout of audioBox markers --- src/client/views/DocumentDecorations.tsx | 3 +- src/client/views/nodes/AudioBox.scss | 8 +- src/client/views/nodes/AudioBox.tsx | 127 +++++++++++-------------- src/client/views/nodes/DocumentLinksButton.tsx | 2 + src/client/views/nodes/DocumentView.tsx | 7 +- src/client/views/nodes/ImageBox.tsx | 2 +- src/client/views/nodes/VideoBox.tsx | 2 +- src/client/views/nodes/WebBox.tsx | 2 +- src/client/views/pdf/PDFViewer.tsx | 2 +- 9 files changed, 77 insertions(+), 78 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index d7b0b5158..c2de78d09 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -62,7 +62,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b @computed get Bounds(): { x: number, y: number, b: number, r: number } { - return SelectionManager.Views().map(dv => dv.getBounds()).reduce((bounds, rect) => + const boudns = SelectionManager.Views().map(dv => dv.getBounds()).reduce((bounds, rect) => !rect ? bounds : { x: Math.min(rect.left, bounds.x), @@ -71,6 +71,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b b: Math.max(rect.bottom, bounds.b) }, { x: Number.MAX_VALUE, y: Number.MAX_VALUE, r: Number.MIN_VALUE, b: Number.MIN_VALUE }); + return boudns; } titleBlur = action((commit: boolean) => { diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss index e5bf9088f..aa3705205 100644 --- a/src/client/views/nodes/AudioBox.scss +++ b/src/client/views/nodes/AudioBox.scss @@ -300,10 +300,12 @@ .resizer { position: absolute; + top: 0; right: 0; + pointer-events: all; cursor: ew-resize; height: 100%; - width: 2px; + width: 10px; z-index: 100; } @@ -317,9 +319,11 @@ .left-resizer { position: absolute; left: 0; + top : 0; + pointer-events: all; cursor: ew-resize; height: 100%; - width: 2px; + width: 10px; z-index: 100; } } diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 1c2812e86..98957d655 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -30,6 +30,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment"; import { LinkAnchorBox } from "./LinkAnchorBox"; import { LinkDocPreview } from "./LinkDocPreview"; +import { DocumentManager } from "../../util/DocumentManager"; declare class MediaRecorder { // whatever MediaRecorder has @@ -53,7 +54,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent; _duration = 0; _markerStart: number = 0; - private _currMarker: any; + _currMarker: any; @observable _visible: boolean = false; @observable _markerEnd: number = 0; @@ -93,8 +94,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent { + return this._ele?.currentTime ? this.createMarker(this._ele?.currentTime) : this.rootDoc; + } @action componentDidMount() { if (!this.dataDoc.markerAmount) { this.dataDoc.markerAmount = 0; } + this.props.setContentView?.(this); this.audioState = this.path ? "paused" : undefined; this._disposers.linkPlay = reaction(() => this.layoutDoc.scrollToLinkID, scrollLinkId => { if (scrollLinkId) { - DocListCast(this.dataDoc.links).filter(l => l[Id] === scrollLinkId).map(l => { + this.links.filter(l => l[Id] === scrollLinkId).map(l => { const { linkTime } = this.getLinkData(l); setTimeout(() => { this.playFromTime(linkTime); Doc.linkFollowHighlight(l); }, 250); }); @@ -139,7 +144,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent { const sel = selected.length ? selected[0].props.Document : undefined; let link; - sel && DocListCast(this.dataDoc.links).forEach(l => { + sel && this.links.forEach(l => { if (l.anchor1 === sel || l.anchor2 === sel && !sel.audioStart) { link = this.playLink(sel); } @@ -153,38 +158,30 @@ export class AudioBox extends ViewBoxAnnotatableComponent AudioBox._scrubTime, (time) => this.layoutDoc.playOnSelect && this.playFromTime(AudioBox._scrubTime)); this._disposers.audioStart = reaction( - () => this.Document._audioStart, - (audioStart) => { - if (audioStart !== undefined) { - if (this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) { - const delay = this._audioRef.current ? 0 : 250; // wait for mainCont and try again to play - const startTime: number = NumCast(this.Document._audioStart); - setTimeout(() => this._audioRef.current && this.playFrom(startTime), delay); - setTimeout(() => { this.Document._currentTimecode = startTime; this.Document._audioStart = undefined; }, 10 + delay); - } - } - }, + () => !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc && this.props.renderDepth !== -1 ? Cast(this.Document._audioStart, "number", null) : undefined, + audioStart => audioStart !== undefined && setTimeout(() => { + this._audioRef.current && this.playFrom(audioStart); + setTimeout(() => { + this.Document._currentTimecode = audioStart; + this.Document._audioStart = undefined; + }, 10); + }, this._audioRef.current ? 0 : 250), // wait for mainCont and try again to play { fireImmediately: true } ); this._disposers.audioStop = reaction( - () => this.Document._audioStop, - (audioStop) => { - if (audioStop !== undefined) { - if (this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc) { - const delay = this._audioRef.current ? 0 : 250; // wait for mainCont and try again to play - setTimeout(() => this._audioRef.current && this.pause(), delay); - setTimeout(() => { this.Document._audioStop = undefined; }, 10 + delay); - } - } - }, + () => this.props.renderDepth !== -1 && !LinkDocPreview.TargetDoc && !FormattedTextBoxComment.linkDoc ? Cast(this.Document._audioStop, "number", null) : undefined, + audioStop => audioStop !== undefined && setTimeout(() => { + this._audioRef.current && this.pause(); + setTimeout(() => this.Document._audioStop = undefined, 10); + }, this._audioRef.current ? 0 : 250), // wait for mainCont and try again to play { fireImmediately: true } ); } playLink = (doc: Doc) => { let link = false; - !Doc.AreProtosEqual(doc, this.props.Document) && DocListCast(this.props.Document.links).forEach(l => { + !Doc.AreProtosEqual(doc, this.props.Document) && this.links.forEach(l => { if (l.anchor1 === doc || l.anchor2 === doc) { const { la1, la2, linkTime } = this.getLinkData(l); let startTime = linkTime; @@ -211,7 +208,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent this.dataDoc.duration = htmlEle.duration); - DocListCast(this.dataDoc.links).map(l => { + this.links.map(l => { const { la1, linkTime } = this.getLinkData(l); if (linkTime > NumCast(this.layoutDoc._currentTimecode) && linkTime < htmlEle.currentTime) { Doc.linkFollowHighlight(la1); @@ -232,6 +229,13 @@ export class AudioBox extends ViewBoxAnnotatableComponent { + DocumentManager.Instance.getDocumentView(anchorDoc)?.select(false); + if (this.layoutDoc.playOnClick) this.playFrom(seekTimeInSeconds, endTime); + else this._ele && (this._ele.currentTime = this.layoutDoc._currentTimecode = seekTimeInSeconds); + } // play back the audio from time @action playFrom = (seekTimeInSeconds: number, endTime: number = this.audioDuration) => { @@ -427,6 +431,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent([marker]); } + return marker; } // starting the drag event for marker resizing @@ -436,12 +441,12 @@ export class AudioBox extends ViewBoxAnnotatableComponent screen_delta / width * this.audioDuration; setupMoveUpEvents(this, e, - (e: PointerEvent) => { + (e) => { const rect = (e.target as any).getBoundingClientRect(); this.changeMarker(this._currMarker, toTimeline(e.clientX - rect.x, rect.width)); return false; }, - (e: PointerEvent) => { + (e) => { const rect = (e.target as any).getBoundingClientRect(); this._ele!.currentTime = this.layoutDoc._currentTimecode = toTimeline(e.clientX - rect.x, rect.width); this._timeline?.releasePointerCapture(e.pointerId); @@ -452,7 +457,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent { - DocListCast(this.dataDoc[this.annotationKey]).filter(marker => this.isSame(marker, m)).forEach(marker => + this.markerDocs.filter(marker => this.isSame(marker, m)).forEach(marker => this._left ? marker.audioStart = time : marker.audioEnd = time); } @@ -507,6 +512,9 @@ export class AudioBox extends ViewBoxAnnotatableComponent; } + @computed get markerDocs() { return DocListCast(this.dataDoc[this.annotationKey]); } + @computed get links() { return DocListCast(this.dataDoc.links); } + // returns the audio waveform @computed get waveform() { const audioBuckets = Cast(this.dataDoc.audioBuckets, listSpec("number"), []); @@ -539,12 +547,13 @@ export class AudioBox extends ViewBoxAnnotatableComponent AudioBox.RangeScript; labelScript = () => AudioBox.LabelScript; - static audioStyleProvider = (doc: Doc | undefined, props: Opt, property: string) => { + audioStyleProvider = (doc: Doc | undefined, props: Opt, property: string) => { if (property === StyleProp.BackgroundColor) return "transparent"; if (property === StyleProp.PointerEvents) return "none"; + return this.props.styleProvider?.(doc, props, property); } markerStyle = (doc: Opt, props: Opt, property: string): any => { - return property.startsWith("backgroundColor") ? "dimGrey" : this.props.styleProvider?.(doc, props, property); + return property.startsWith("backgroundColor") ? "dimgrey" : this.props.styleProvider?.(doc, props, property); } render() { const interactive = SnappingManager.GetIsDragging() || this.active() ? "-interactive" : ""; @@ -561,9 +570,9 @@ export class AudioBox extends ViewBoxAnnotatableComponent this.props.ScreenToLocalTransform().translate(-x, -y) : this.props.ScreenToLocalTransform} + ScreenToLocalTransform={x && y ? () => this.props.ScreenToLocalTransform().translate(-x - 4, -y - 3) : this.props.ScreenToLocalTransform} parentActive={returnTrue} - onClick={this.layoutDoc.playOnClick ? script : undefined} + onClick={script} ignoreAutoHeight={false} bringToFront={emptyFunction} scriptContext={this} />; @@ -601,9 +610,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent { e.stopPropagation(); e.preventDefault(); }} onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { - const rect = (e.target as any).getBoundingClientRect(); - - if (e.target !== this._audioRef.current) { + const rect = this._timeline?.getBoundingClientRect();// (e.target as any).getBoundingClientRect(); + if (rect && e.target !== this._audioRef.current) { const wasPaused = this.audioState === "paused"; this._ele!.currentTime = this.layoutDoc._currentTimecode = (e.clientX - rect.x) / rect.width * this.audioDuration; wasPaused && this.pause(); @@ -615,57 +623,38 @@ export class AudioBox extends ViewBoxAnnotatableComponent {this.waveform} - {DocListCast(this.dataDoc[this.annotationKey]).map((m, i) => { + {this.markerDocs.map((m, i) => { const isOverlap = this.isOverlap(m); return !m.isLabel ? this.layoutDoc.hideMarkers ? (null) :
{ this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation(); }} > -
this.onPointerDown(e, m, true)}>
+
this.onPointerDown(e, m, true)} /> {markerDoc(m, this.rangeScript, playheadWidth + NumCast(m.audioStart) / this.audioDuration * timelineContentWidth, .1 * this.props.PanelHeight() + isOverlap / (this.dataDoc.markerAmount + 1) * timelineContentHeight, timelineContentWidth * (NumCast(m.audioEnd) - NumCast(m.audioStart)) / this.audioDuration, timelineContentHeight / (this.dataDoc.markerAmount + 1))} -
this.onPointerDown(e, m, false)}>
+
this.onPointerDown(e, m, false)} />
: this.layoutDoc.hideLabels ? (null) :
- {markerDoc(m, this.labelScript)} + style={{ left: `${NumCast(m.audioStart) / this.audioDuration * 100}%` }} + onClick={e => { this.playFrom(NumCast(m.audioStart)); e.stopPropagation(); }}> + {markerDoc(m, this.labelScript, + playheadWidth + NumCast(m.audioStart) / this.audioDuration * timelineContentWidth, + .1 * this.props.PanelHeight(), + 10, 10)}
; })} - {DocListCast(this.dataDoc.links).map((l, i) => { - const { la1, la2, linkTime } = this.getLinkData(l); - let startTime = linkTime; - if (la2.audioStart && !la2.audioEnd) { - startTime = NumCast(la2.audioStart); - } - - return !linkTime ? (null) : -
e.stopPropagation()}> - -
Doc.linkFollowHighlight(la1)} - onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { this.playFrom(startTime); e.stopPropagation(); e.preventDefault(); } }} /> -
; - })} {this._visible ? this.selectionContainer : null}
{ e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc._currentTimecode) / this.audioDuration * 100}%`, pointerEvents: "none" }} /> diff --git a/src/client/views/nodes/DocumentLinksButton.tsx b/src/client/views/nodes/DocumentLinksButton.tsx index e7a94580a..2cac2d0b8 100644 --- a/src/client/views/nodes/DocumentLinksButton.tsx +++ b/src/client/views/nodes/DocumentLinksButton.tsx @@ -160,6 +160,8 @@ export class DocumentLinksButton extends React.Component boolean; export type DocFocusFunc = (doc: Doc, willZoom?: boolean, scale?: number, afterFocus?: DocAfterFocusFunc, dontCenter?: boolean, focused?: boolean) => void; @@ -52,6 +52,7 @@ export interface DocumentViewSharedProps { fitContentsToDoc?: boolean; // used by freeformview to fit its contents to its panel. corresponds to _fitToBox property on a Document ContainingCollectionView: Opt; ContainingCollectionDoc: Opt; + setContentView?: (view: { getAnchor: () => Doc }) => any, CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView; PanelWidth: () => number; PanelHeight: () => number; @@ -691,9 +692,10 @@ export class DocumentViewInternal extends DocComponent this.ContentScale; onClickFunc = () => this.onClickHandler; makeLink = () => this.props.DocumentView._link; // pass the link placeholde to child views so they can react to make a specialized anchor. This is essentially a function call to the descendants since the value of the _link variable will immediately get set back to undefined. + setContentView = (view: { getAnchor: () => Doc }) => this._componentView = view; @observable contentsActive: () => boolean = returnFalse; @action setContentsActive = (setActive: () => boolean) => this.contentsActive = setActive; - + _componentView: { getAnchor: () => Doc } | undefined; @computed get contents() { TraceMobx(); return
-
- - anno.mixBlendMode) ? "hard-light" : undefined, transform: `scale(${this._zoomed})` }}> - Date: Thu, 14 Jan 2021 10:33:12 -0500 Subject: changed audio labels to allow text display --- src/client/views/StyleProvider.tsx | 1 + src/client/views/nodes/AudioBox.scss | 3 +-- src/client/views/nodes/AudioBox.tsx | 8 ++------ src/client/views/nodes/LabelBox.tsx | 3 ++- 4 files changed, 6 insertions(+), 9 deletions(-) (limited to 'src') diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 5a3abba2d..8560f38cb 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -108,6 +108,7 @@ export function DefaultStyleProvider(doc: Opt, props: Opt, props: Opt, property: string): any => { - return property.startsWith("backgroundColor") ? "dimgrey" : this.props.styleProvider?.(doc, props, property); - } render() { const interactive = SnappingManager.GetIsDragging() || this.active() ? "-interactive" : ""; this._first = true; // for indicating the first marker that is rendered @@ -564,7 +561,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent width : this.props.PanelWidth} PanelHeight={height ? () => height : this.props.PanelHeight} focus={() => this.playLink(mark)} - styleProvider={this.markerStyle} pointerEvents={"all"} rootSelected={returnFalse} LayoutTemplate={undefined} diff --git a/src/client/views/nodes/LabelBox.tsx b/src/client/views/nodes/LabelBox.tsx index bc2090a33..3448a4abd 100644 --- a/src/client/views/nodes/LabelBox.tsx +++ b/src/client/views/nodes/LabelBox.tsx @@ -67,6 +67,7 @@ export class LabelBox extends ViewBoxBaseComponent !this.paramsDoc[p]); params?.map(p => DocListCast(this.paramsDoc[p])); // bcz: really hacky form of prefetching ... + const label = StrCast(this.rootDoc[this.fieldKey], StrCast(this.rootDoc.title)); return (
this.clicked = !this.clicked)} @@ -88,7 +89,7 @@ export class LabelBox extends ViewBoxBaseComponent - {StrCast(this.rootDoc[this.fieldKey], StrCast(this.rootDoc.title))} + {label.startsWith("#") ? (null) : label}
{!missingParams?.length ? (null) : missingParams.map(m =>
{m}
)} -- cgit v1.2.3-70-g09d2 From ad0cad318eb04199a0a68752b74374ff8f66a3be Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 14 Jan 2021 11:24:12 -0500 Subject: fixed rendering of labels in audioBox's to use standard dash-style provider stuff. added double click to play --- src/client/views/StyleProvider.tsx | 3 ++ src/client/views/nodes/AudioBox.scss | 2 - src/client/views/nodes/AudioBox.tsx | 81 +++++++++++++++++++-------------- src/client/views/nodes/DocumentView.tsx | 4 +- 4 files changed, 53 insertions(+), 37 deletions(-) (limited to 'src') diff --git a/src/client/views/StyleProvider.tsx b/src/client/views/StyleProvider.tsx index 8560f38cb..1d822439a 100644 --- a/src/client/views/StyleProvider.tsx +++ b/src/client/views/StyleProvider.tsx @@ -138,6 +138,9 @@ export function DefaultStyleProvider(doc: Opt, props: Opt { DocumentManager.Instance.getDocumentView(anchorDoc)?.select(false); - if (this.layoutDoc.playOnClick) this.playFrom(seekTimeInSeconds, endTime); - else this._ele && (this._ele.currentTime = this.layoutDoc._currentTimecode = seekTimeInSeconds); + this.playFrom(seekTimeInSeconds, endTime); + } + + // play back the audio from time + @action + clickMarker = (anchorDoc: Doc, seekTimeInSeconds: number, endTime: number = this.audioDuration) => { + if (this.layoutDoc.playOnClick) this.playOnClick(anchorDoc, seekTimeInSeconds, endTime); + else { + DocumentManager.Instance.getDocumentView(anchorDoc)?.select(false); + this._ele && (this._ele.currentTime = this.layoutDoc._currentTimecode = seekTimeInSeconds); + } } // play back the audio from time @action @@ -523,7 +536,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent AudioBox.RangeScript; - labelScript = () => AudioBox.LabelScript; - audioStyleProvider = (doc: Doc | undefined, props: Opt, property: string) => { - if (property === StyleProp.BackgroundColor) return "transparent"; - if (property === StyleProp.PointerEvents) return "none"; - return this.props.styleProvider?.(doc, props, property); + rangeClickScript = () => AudioBox.RangeScript; + labelClickScript = () => AudioBox.LabelScript; + rangePlayScript = () => AudioBox.RangePlayScript; + labelPlayScript = () => AudioBox.LabelPlayScript; + renderMarker = (mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), x: number, y: number, width: number, height: number) => { + return width} + PanelHeight={() => height} + focus={() => this.playLink(mark)} + rootSelected={returnFalse} + LayoutTemplate={undefined} + ContainingCollectionDoc={this.props.Document} + removeDocument={this.removeDocument} + ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-x - 4, -y - 3)} + parentActive={returnTrue} + onClick={script} + onDoubleClick={this.layoutDoc.playOnClick ? undefined : doublescript} + ignoreAutoHeight={false} + bringToFront={emptyFunction} + scriptContext={this} />; } render() { const interactive = SnappingManager.GetIsDragging() || this.active() ? "-interactive" : ""; this._first = true; // for indicating the first marker that is rendered - const markerDoc = (mark: Doc, script: undefined | (() => ScriptField), x?: number, y?: number, width?: number, height?: number) => { - return width : this.props.PanelWidth} - PanelHeight={height ? () => height : this.props.PanelHeight} - focus={() => this.playLink(mark)} - pointerEvents={"all"} - rootSelected={returnFalse} - LayoutTemplate={undefined} - ContainingCollectionDoc={this.props.Document} - removeDocument={this.removeDocument} - ScreenToLocalTransform={x && y ? () => this.props.ScreenToLocalTransform().translate(-x - 4, -y - 3) : this.props.ScreenToLocalTransform} - parentActive={returnTrue} - onClick={script} - ignoreAutoHeight={false} - bringToFront={emptyFunction} - scriptContext={this} />; - }; + const heightPercent = 80; const playheadWidth = 30; const timelineContentWidth = this.props.PanelWidth() - playheadWidth; const timelineContentHeight = (this.props.PanelHeight() * heightPercent / 100) * heightPercent / 100; // panelHeight * heightPercent is player height. * heightPercent is timeline height (as per css inline) - return
+ return
{!this.path ?
@@ -586,10 +599,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent e.stopPropagation()}>
- +
- +
{formatTime(Math.round(NumCast(this.layoutDoc._currentTimecode)))}
@@ -633,7 +646,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent { this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation(); }} >
this.onPointerDown(e, m, true)} /> - {markerDoc(m, this.rangeScript, + {this.renderMarker(m, this.rangeClickScript, this.rangePlayScript, playheadWidth + NumCast(m.audioStart) / this.audioDuration * timelineContentWidth, .1 * this.props.PanelHeight() + isOverlap / (this.dataDoc.markerAmount + 1) * timelineContentHeight, timelineContentWidth * (NumCast(m.audioEnd) - NumCast(m.audioStart)) / this.audioDuration, @@ -645,7 +658,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent { this.playFrom(NumCast(m.audioStart)); e.stopPropagation(); }}> - {markerDoc(m, this.labelScript, + {this.renderMarker(m, this.labelClickScript, this.labelPlayScript, playheadWidth + NumCast(m.audioStart) / this.audioDuration * timelineContentWidth, .1 * this.props.PanelHeight(), 10, 10)} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index b44c15a78..98995d040 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -379,14 +379,16 @@ export class DocumentViewInternal extends DocComponent this.onDoubleClickHandler.script.run({ this: this.layoutDoc, self: this.rootDoc, + scriptContext: this.props.scriptContext, thisContainer: this.props.ContainingCollectionDoc, + documentView: this.props.DocumentView, shiftKey: e.shiftKey }, console.log); undoBatch(func)(); } else if (!Doc.IsSystem(this.props.Document)) { if (this.props.Document.type === DocumentType.INK) { InkStrokeProperties.Instance && (InkStrokeProperties.Instance._controlBtn = true); - } else { + } else if (this.props.Document.type !== DocumentType.LABEL) { UndoManager.RunInBatch(() => { const fullScreenDoc = Cast(this.props.Document._fullScreenView, Doc, null) || this.props.Document; this.props.addDocTab(fullScreenDoc, "add"); -- cgit v1.2.3-70-g09d2 From 6ce848be82dcb2c3b8bffe69282305b348d639a2 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 14 Jan 2021 11:58:25 -0500 Subject: fixed stacking behavior of what audio regions that have no end --- src/client/views/DocumentButtonBar.tsx | 2 +- src/client/views/collections/TabDocView.tsx | 2 +- src/client/views/nodes/AudioBox.tsx | 66 +++++++++++++++-------------- 3 files changed, 36 insertions(+), 34 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentButtonBar.tsx b/src/client/views/DocumentButtonBar.tsx index 3eabb294d..a2bd0aad9 100644 --- a/src/client/views/DocumentButtonBar.tsx +++ b/src/client/views/DocumentButtonBar.tsx @@ -190,7 +190,7 @@ export class DocumentButtonBar extends React.Component<{ views: () => (DocumentV
{SelectionManager.Views().length > 1 ? "Pin multiple documents to presentation" : "Pin to presentation"}
}>
this.props.views().map(view => view && TabDocView.PinDoc(view.props.Document /*, { setPosition: true }*/)))}> + onClick={undoBatch(e => this.props.views().map(view => view && TabDocView.PinDoc(view.props.Document, { setPosition: e.shiftKey ? true : undefined })))}>
; diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx index 09f709a5e..5ca069fb9 100644 --- a/src/client/views/collections/TabDocView.tsx +++ b/src/client/views/collections/TabDocView.tsx @@ -196,7 +196,7 @@ export class TabDocView extends React.Component { pinDoc.x = doc.x; pinDoc.presHideAfter = true; pinDoc.presHideBefore = true; - pinDoc.title = doc.title + "- Spotlight"; + pinDoc.title = doc.title + " (move)"; pinDoc.presMovement = PresMovement.None; } if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true; diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 141f90e83..36df09338 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -17,20 +17,19 @@ import { emptyFunction, formatTime, numberRange, returnFalse, returnTrue, setupM import { Docs, DocUtils } from "../../documents/Documents"; import { Networking } from "../../Network"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; +import { DocumentManager } from "../../util/DocumentManager"; import { Scripting } from "../../util/Scripting"; import { SelectionManager } from "../../util/SelectionManager"; import { SnappingManager } from "../../util/SnappingManager"; import { ContextMenu } from "../ContextMenu"; import { ContextMenuProps } from "../ContextMenuItem"; import { ViewBoxAnnotatableComponent } from "../DocComponent"; -import { StyleProp } from "../StyleProvider"; import "./AudioBox.scss"; -import { DocumentView, DocumentViewProps } from "./DocumentView"; +import { DocumentView } from "./DocumentView"; import { FieldView, FieldViewProps } from './FieldView'; import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment"; -import { LinkAnchorBox } from "./LinkAnchorBox"; import { LinkDocPreview } from "./LinkDocPreview"; -import { DocumentManager } from "../../util/DocumentManager"; +import { computedFn } from "mobx-utils"; declare class MediaRecorder { // whatever MediaRecorder has @@ -46,6 +45,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent 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.hideLabels ? "Don't hide" : "Hide") + " label markers", event: () => this.layoutDoc.hideLabels = !this.layoutDoc.hideLabels, 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" }); ContextMenu.Instance?.addItem({ description: "Options...", subitems: funcs, icon: "asterisk" }); } @@ -409,6 +409,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent { + this.props.select(false); const rect = (e.target as any).getBoundingClientRect(); const toTimeline = (screen_delta: number) => screen_delta / rect.width * this.audioDuration; this._markerStart = this._markerEnd = toTimeline(e.clientX - rect.x); @@ -479,11 +480,11 @@ export class AudioBox extends ViewBoxAnnotatableComponent { - const increment = this.audioDuration / 500; + const increment = this.audioDuration / AudioBox.NUMBER_OF_BUCKETS; this._count = []; - for (let i = 0; i < 500; i++) { + for (let i = 0; i < AudioBox.NUMBER_OF_BUCKETS; i++) { this._count.push([increment * i, 0]); } } @@ -495,9 +496,10 @@ export class AudioBox extends ViewBoxAnnotatableComponent= m.audioStart && this._count[i][0] <= m.audioEnd) { + const timelineContentWidth = this.props.PanelWidth() - AudioBox.playheadWidth; + const audioEnd = m.audioEnd === undefined ? m.audioStart + 10 / timelineContentWidth * this.audioDuration : m.audioEnd; + for (let i = 0; i < AudioBox.NUMBER_OF_BUCKETS; i++) { + if (this._count[i][0] >= m.audioStart && this._count[i][0] <= audioEnd) { this._count[i][1]++; if (this._count[i][1] > max) { @@ -506,8 +508,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent= m.audioStart && this._count[i][0] <= m.audioEnd) { + for (let i = 0; i < AudioBox.NUMBER_OF_BUCKETS; i++) { + if (this._count[i][0] >= m.audioStart && this._count[i][0] <= audioEnd) { this._count[i][1] = max; } } @@ -561,7 +563,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent AudioBox.LabelScript; rangePlayScript = () => AudioBox.RangePlayScript; labelPlayScript = () => AudioBox.LabelPlayScript; - renderMarker = (mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), x: number, y: number, width: number, height: number) => { + renderMarker = computedFn(function (this: AudioBox, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), x: number, y: number, width: number, height: number) { return width} @@ -578,15 +580,13 @@ export class AudioBox extends ViewBoxAnnotatableComponent; - } + }); render() { const interactive = SnappingManager.GetIsDragging() || this.active() ? "-interactive" : ""; this._first = true; // for indicating the first marker that is rendered - const heightPercent = 80; - const playheadWidth = 30; - const timelineContentWidth = this.props.PanelWidth() - playheadWidth; - const timelineContentHeight = (this.props.PanelHeight() * heightPercent / 100) * heightPercent / 100; // panelHeight * heightPercent is player height. * heightPercent is timeline height (as per css inline) + const timelineContentWidth = this.props.PanelWidth() - AudioBox.playheadWidth; + const timelineContentHeight = (this.props.PanelHeight() * AudioBox.heightPercent / 100) * AudioBox.heightPercent / 100; // panelHeight * heightPercent is player height. * heightPercent is timeline height (as per css inline) return
:
-
-
-
+
+
{ e.stopPropagation(); e.preventDefault(); }} onPointerDown={e => { if (e.button === 0 && !e.ctrlKey) { @@ -634,32 +634,34 @@ export class AudioBox extends ViewBoxAnnotatableComponent {this.markerDocs.map((m, i) => { const isOverlap = this.isOverlap(m); - return !m.isLabel ? - this.layoutDoc.hideMarkers ? (null) : + const left = AudioBox.playheadWidth + NumCast(m.audioStart) / this.audioDuration * timelineContentWidth; + return this.layoutDoc.hideMarkers ? (null) : + !m.isLabel ?
{ this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation(); }} >
this.onPointerDown(e, m, true)} /> {this.renderMarker(m, this.rangeClickScript, this.rangePlayScript, - playheadWidth + NumCast(m.audioStart) / this.audioDuration * timelineContentWidth, + left, .1 * this.props.PanelHeight() + isOverlap / (this.dataDoc.markerAmount + 1) * timelineContentHeight, timelineContentWidth * (NumCast(m.audioEnd) - NumCast(m.audioStart)) / this.audioDuration, timelineContentHeight / (this.dataDoc.markerAmount + 1))}
this.onPointerDown(e, m, false)} />
- : - this.layoutDoc.hideLabels ? (null) : + :
{ this.playFrom(NumCast(m.audioStart)); e.stopPropagation(); }}> {this.renderMarker(m, this.labelClickScript, this.labelPlayScript, - playheadWidth + NumCast(m.audioStart) / this.audioDuration * timelineContentWidth, + left, .1 * this.props.PanelHeight(), 10, 10)}
; -- cgit v1.2.3-70-g09d2 From a3517dec4d76b4534d05f16e6a2da4aa519e8258 Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 14 Jan 2021 14:25:14 -0500 Subject: cleaned up audiobox render code. display resize handles now. --- src/client/views/nodes/AudioBox.scss | 11 ++- src/client/views/nodes/AudioBox.tsx | 160 ++++++++++++++++------------------- 2 files changed, 83 insertions(+), 88 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss index 9a8ad71c8..36cc22d79 100644 --- a/src/client/views/nodes/AudioBox.scss +++ b/src/client/views/nodes/AudioBox.scss @@ -277,7 +277,7 @@ } } - .audiobox-marker-container1, + .audiobox-marker-timeline, .audiobox-marker-minicontainer { position: absolute; width: 10px; @@ -285,6 +285,13 @@ top: 2.5%; border-radius: 5px; + .left-resizer { + background: dimgrey; + } + .resizer { + background: dimgrey; + } + .audiobox-marker { position: relative; height: calc(100% - 15px); @@ -325,7 +332,7 @@ } } - .audiobox-marker-container1:hover, + .audiobox-marker-timeline:hover, .audiobox-marker-minicontainer:hover { opacity: 0.8; } diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 36df09338..d151ec413 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -30,6 +30,7 @@ import { FieldView, FieldViewProps } from './FieldView'; import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment"; import { LinkDocPreview } from "./LinkDocPreview"; import { computedFn } from "mobx-utils"; +import { ObservableValue } from "mobx/lib/internal"; declare class MediaRecorder { // whatever MediaRecorder has @@ -54,9 +55,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent = this.layoutDoc._height; @@ -409,27 +407,33 @@ export class AudioBox extends ViewBoxAnnotatableComponent { - this.props.select(false); - const rect = (e.target as any).getBoundingClientRect(); - const toTimeline = (screen_delta: number) => screen_delta / rect.width * this.audioDuration; - this._markerStart = this._markerEnd = toTimeline(e.clientX - rect.x); - setupMoveUpEvents(this, e, - action((e: PointerEvent) => { - this._visible = true; - this._markerEnd = toTimeline(e.clientX - rect.x); - if (this._markerEnd < this._markerStart) { - const tmp = this._markerStart; - this._markerStart = this._markerEnd; - this._markerEnd = tmp; - } - return false; - }), - action((e: PointerEvent, movement: number[]) => { - (Math.abs(movement[0]) > 15) && this.createMarker(this._markerStart, toTimeline(e.clientX - rect.x)); - this._visible = false; - }), - (e: PointerEvent) => e.shiftKey && this.createMarker(this._ele!.currentTime) - ); + const rect = this._timeline?.getBoundingClientRect();// (e.target as any).getBoundingClientRect(); + if (rect && e.target !== this._audioRef.current) { + const wasPaused = this.audioState === "paused"; + this._ele!.currentTime = this.layoutDoc._currentTimecode = (e.clientX - rect.x) / rect.width * this.audioDuration; + wasPaused && this.pause(); + + this.props.select(false) + const toTimeline = (screen_delta: number) => screen_delta / rect.width * this.audioDuration; + this._markerStart = this._markerEnd = toTimeline(e.clientX - rect.x); + setupMoveUpEvents(this, e, + action(e => { + this._selectRegionVisible = true; + this._markerEnd = toTimeline(e.clientX - rect.x); + if (this._markerEnd < this._markerStart) { + const tmp = this._markerStart; + this._markerStart = this._markerEnd; + this._markerEnd = tmp; + } + return false; + }), + action((e, movement) => { + (Math.abs(movement[0]) > 15) && this.createMarker(this._markerStart, toTimeline(e.clientX - rect.x)); + this._selectRegionVisible = false; + }), + e => e.shiftKey && this.createMarker(this._ele!.currentTime) + ); + } } @action @@ -521,7 +525,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent; @@ -563,23 +567,37 @@ export class AudioBox extends ViewBoxAnnotatableComponent AudioBox.LabelScript; rangePlayScript = () => AudioBox.RangePlayScript; labelPlayScript = () => AudioBox.LabelPlayScript; + renderInner = computedFn(function (this: AudioBox, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), x: number, y: number, width: number, height: number) { + let marker = observable({ view: undefined as any }); + return { + marker, view: marker.view = r)} + Document={mark} + PanelWidth={() => width} + PanelHeight={() => height} + focus={() => this.playLink(mark)} + rootSelected={returnFalse} + LayoutTemplate={undefined} + ContainingCollectionDoc={this.props.Document} + removeDocument={this.removeDocument} + ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-x - 4, -y - 3)} + parentActive={returnTrue} + onClick={script} + onDoubleClick={this.layoutDoc.playOnClick ? undefined : doublescript} + ignoreAutoHeight={false} + bringToFront={emptyFunction} + scriptContext={this} /> + }; + }); renderMarker = computedFn(function (this: AudioBox, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), x: number, y: number, width: number, height: number) { - return width} - PanelHeight={() => height} - focus={() => this.playLink(mark)} - rootSelected={returnFalse} - LayoutTemplate={undefined} - ContainingCollectionDoc={this.props.Document} - removeDocument={this.removeDocument} - ScreenToLocalTransform={() => this.props.ScreenToLocalTransform().translate(-x - 4, -y - 3)} - parentActive={returnTrue} - onClick={script} - onDoubleClick={this.layoutDoc.playOnClick ? undefined : doublescript} - ignoreAutoHeight={false} - bringToFront={emptyFunction} - scriptContext={this} />; + const inner = this.renderInner(mark, script, doublescript, x, y, width, height); + return <> + {inner.view} + {!inner.marker.view || !SelectionManager.IsSelected(inner.marker.view) ? (null) : + <> +
this.onPointerDown(e, mark, true)} /> +
this.onPointerDown(e, mark, false)} /> + } + ; }); render() { const interactive = SnappingManager.GetIsDragging() || this.active() ? "-interactive" : ""; @@ -617,57 +635,27 @@ export class AudioBox extends ViewBoxAnnotatableComponent
{ e.stopPropagation(); e.preventDefault(); }} - onPointerDown={e => { - if (e.button === 0 && !e.ctrlKey) { - const rect = this._timeline?.getBoundingClientRect();// (e.target as any).getBoundingClientRect(); - if (rect && e.target !== this._audioRef.current) { - const wasPaused = this.audioState === "paused"; - this._ele!.currentTime = this.layoutDoc._currentTimecode = (e.clientX - rect.x) / rect.width * this.audioDuration; - wasPaused && this.pause(); - } - - this.onPointerDownTimeline(e); - } - }}> + onPointerDown={e => e.button === 0 && !e.ctrlKey && this.onPointerDownTimeline(e)}>
{this.waveform}
{this.markerDocs.map((m, i) => { const isOverlap = this.isOverlap(m); - const left = AudioBox.playheadWidth + NumCast(m.audioStart) / this.audioDuration * timelineContentWidth; + const left = NumCast(m.audioStart) / this.audioDuration * timelineContentWidth; + const top = isOverlap / (this.dataDoc.markerAmount + 1) * timelineContentHeight; + const timespan = m.audioEnd === undefined ? 10 / timelineContentWidth * this.audioDuration : NumCast(m.audioEnd) - NumCast(m.audioStart); return this.layoutDoc.hideMarkers ? (null) : - !m.isLabel ? -
{ this.playFrom(NumCast(m.audioStart), NumCast(m.audioEnd)); e.stopPropagation(); }} > -
this.onPointerDown(e, m, true)} /> - {this.renderMarker(m, this.rangeClickScript, this.rangePlayScript, - left, - .1 * this.props.PanelHeight() + isOverlap / (this.dataDoc.markerAmount + 1) * timelineContentHeight, - timelineContentWidth * (NumCast(m.audioEnd) - NumCast(m.audioStart)) / this.audioDuration, - timelineContentHeight / (this.dataDoc.markerAmount + 1))} -
this.onPointerDown(e, m, false)} /> -
- : -
{ this.playFrom(NumCast(m.audioStart)); e.stopPropagation(); }}> - {this.renderMarker(m, this.labelClickScript, this.labelPlayScript, - left, - .1 * this.props.PanelHeight(), - 10, 10)} -
; +
{ this.playFrom(NumCast(m.audioStart), Cast(m.audioEnd, "number", null)); e.stopPropagation(); }} > + {this.renderMarker(m, this.rangeClickScript, this.rangePlayScript, + left + AudioBox.playheadWidth, + (1 - AudioBox.heightPercent / 100) / 2 * this.props.PanelHeight() + top, + timelineContentWidth * timespan / this.audioDuration, + timelineContentHeight / (this.dataDoc.markerAmount + 1))} +
; })} - {this._visible ? this.selectionContainer : null} - + {this.selectionContainer}
{ e.stopPropagation(); e.preventDefault(); }} style={{ left: `${NumCast(this.layoutDoc._currentTimecode) / this.audioDuration * 100}%`, pointerEvents: "none" }} /> {this.audio}
-- cgit v1.2.3-70-g09d2 From 8176561879eecadec6a2f8926f08db93807aa16e Mon Sep 17 00:00:00 2001 From: bobzel Date: Thu, 14 Jan 2021 14:41:09 -0500 Subject: fixed playing anchors when following a link to audio --- src/client/views/nodes/AudioBox.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index d151ec413..21dfec888 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -197,12 +197,12 @@ export class AudioBox extends ViewBoxAnnotatableComponent Date: Thu, 14 Jan 2021 17:13:57 -0500 Subject: simplified links to audio to always have a target Doc anchor. updated auto links to audio when recording. fixed making text selection links. --- src/client/documents/Documents.ts | 12 +-- src/client/util/DragManager.ts | 8 +- src/client/views/nodes/AudioBox.tsx | 88 +++++++--------------- src/client/views/nodes/DocumentView.tsx | 17 +---- .../views/nodes/formattedText/FormattedTextBox.tsx | 3 +- 5 files changed, 41 insertions(+), 87 deletions(-) (limited to 'src') diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts index c457fb722..b32cbd3d0 100644 --- a/src/client/documents/Documents.ts +++ b/src/client/documents/Documents.ts @@ -1,4 +1,4 @@ -import { runInAction, action } from "mobx"; +import { action, runInAction } from "mobx"; import { basename, extname } from "path"; import { DateField } from "../../fields/DateField"; import { Doc, DocListCast, DocListCastAsync, Field, HeightSym, Opt, WidthSym } from "../../fields/Doc"; @@ -42,19 +42,19 @@ import { ImageBox } from "../views/nodes/ImageBox"; import { KeyValueBox } from "../views/nodes/KeyValueBox"; import { LabelBox } from "../views/nodes/LabelBox"; import { LinkBox } from "../views/nodes/LinkBox"; +import { LinkDescriptionPopup } from "../views/nodes/LinkDescriptionPopup"; import { PDFBox } from "../views/nodes/PDFBox"; import { PresBox } from "../views/nodes/PresBox"; import { ScreenshotBox } from "../views/nodes/ScreenshotBox"; import { ScriptingBox } from "../views/nodes/ScriptingBox"; import { SliderBox } from "../views/nodes/SliderBox"; +import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox"; import { VideoBox } from "../views/nodes/VideoBox"; import { WebBox } from "../views/nodes/WebBox"; import { PresElementBox } from "../views/presentationview/PresElementBox"; import { SearchBox } from "../views/search/SearchBox"; import { DashWebRTCVideo } from "../views/webcam/DashWebRTCVideo"; import { DocumentType } from "./DocumentTypes"; -import { TaskCompletionBox } from "../views/nodes/TaskCompletedBox"; -import { LinkDescriptionPopup } from "../views/nodes/LinkDescriptionPopup"; const path = require('path'); const defaultNativeImageDim = Number(DFLT_IMAGE_NATIVE_DIM.replace("px", "")); @@ -610,7 +610,7 @@ export namespace Docs { proto.links = ComputedField.MakeFunction("links(self)"); viewDoc.author = Doc.CurrentUserEmail; - viewDoc.type !== DocumentType.LINK && DocUtils.MakeLinkToActiveAudio(viewDoc); + viewDoc.type !== DocumentType.LINK && viewDoc.type !== DocumentType.LABEL && DocUtils.MakeLinkToActiveAudio(viewDoc); viewDoc["acl-Public"] = dataDoc["acl-Public"] = Doc.UserDoc()?.defaultAclPrivate ? SharingPermissions.None : SharingPermissions.Add; viewDoc["acl-Override"] = dataDoc["acl-Override"] = "None"; @@ -1008,10 +1008,10 @@ export namespace DocUtils { }); } - export let ActiveRecordings: Doc[] = []; + export let ActiveRecordings: AudioBox[] = []; export function MakeLinkToActiveAudio(doc: Doc) { - DocUtils.ActiveRecordings.map(d => DocUtils.MakeLink({ doc: doc }, { doc: d }, "audio link", "audio timeline")); + DocUtils.ActiveRecordings.map(d => DocUtils.MakeLink({ doc: doc }, { doc: d.getAnchor() || d.props.Document }, "audio link", "audio timeline")); } export function MakeLink(source: { doc: Doc }, target: { doc: Doc }, linkRelationship: string = "", description: string = "", id?: string, allowParCollectionLink?: boolean, showPopup?: number[]) { diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts index d24348746..52ccfda74 100644 --- a/src/client/util/DragManager.ts +++ b/src/client/util/DragManager.ts @@ -529,15 +529,16 @@ export namespace DragManager { endDrag(); }; const upHandler = (e: PointerEvent) => { - dispatchDrag(eles, e, dragData, xFromLeft, yFromTop, xFromRight, yFromBottom, options, finishDrag); - options?.dragComplete?.(new DragCompleteEvent(false, dragData)); + const complete = new DragCompleteEvent(false, dragData); + dispatchDrag(eles, e, complete, xFromLeft, yFromTop, xFromRight, yFromBottom, options, finishDrag); + options?.dragComplete?.(complete); endDrag(); }; document.addEventListener("pointermove", moveHandler, true); document.addEventListener("pointerup", upHandler); } - function dispatchDrag(dragEles: HTMLElement[], e: PointerEvent, dragData: { [index: string]: any }, + function dispatchDrag(dragEles: HTMLElement[], e: PointerEvent, complete: DragCompleteEvent, xFromLeft: number, yFromTop: number, xFromRight: number, yFromBottom: number, options?: DragOptions, finishDrag?: (e: DragCompleteEvent) => void) { const removed = dragEles.map(dragEle => { const ret = { ele: dragEle, w: dragEle.style.width, h: dragEle.style.height, o: dragEle.style.overflow }; @@ -558,7 +559,6 @@ export namespace DragManager { }); const { thisX, thisY } = snapDrag(e, xFromLeft, yFromTop, xFromRight, yFromBottom); if (target) { - const complete = new DragCompleteEvent(false, dragData); target.dispatchEvent( new CustomEvent("dashPreDrop", { bubbles: true, diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 21dfec888..9f8bdcd57 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -30,7 +30,6 @@ import { FieldView, FieldViewProps } from './FieldView'; import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment"; import { LinkDocPreview } from "./LinkDocPreview"; import { computedFn } from "mobx-utils"; -import { ObservableValue } from "mobx/lib/internal"; declare class MediaRecorder { // whatever MediaRecorder has @@ -46,7 +45,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent disposer?.()); + const ind = DocUtils.ActiveRecordings.indexOf(this); + ind !== -1 && (DocUtils.ActiveRecordings.splice(ind, 1)); } getAnchor = () => { - return this._ele?.currentTime ? this.createMarker(this._ele?.currentTime) : this.rootDoc; + const time = this._ele?.currentTime || Cast(this.props.Document._currentTimecode, "number", null) || (this.audioState === "recording" ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined); + return time ? this.createMarker(time) : this.rootDoc; } + @action componentDidMount() { if (!this.dataDoc.markerAmount) { this.dataDoc.markerAmount = 0; } - this.props.setContentView?.(this); + 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.audioState = this.path ? "paused" : undefined; - this._disposers.linkPlay = reaction(() => this.layoutDoc.scrollToLinkID, - scrollLinkId => { - if (scrollLinkId) { - this.links.filter(l => l[Id] === scrollLinkId).map(l => { - const { linkTime } = this.getLinkData(l); - setTimeout(() => { this.playFromTime(linkTime); Doc.linkFollowHighlight(l); }, 250); - }); - Doc.SetInPlace(this.layoutDoc, "scrollToLinkID", undefined, false); - } - }, { fireImmediately: true }); - - // for play when link is selected - this._disposers.reaction = reaction(() => SelectionManager.Views(), - selected => { - const sel = selected.length ? selected[0].props.Document : undefined; - let link; - sel && this.links.forEach(l => { - if (l.anchor1 === sel || l.anchor2 === sel && !sel.audioStart) { - link = this.playLink(sel); - } - }); - // for links created during recording - if (!link) { - this.layoutDoc.playOnSelect && this.recordingStart && sel && sel.creationDate && !Doc.AreProtosEqual(sel, this.props.Document) && this.playFromTime(DateCast(sel.creationDate).date.getTime()); - this.layoutDoc.playOnSelect && this.recordingStart && !sel && this.pause(); - } - }); + this._disposers.scrubbing = reaction(() => AudioBox._scrubTime, (time) => this.layoutDoc.playOnSelect && this.playFromTime(AudioBox._scrubTime)); this._disposers.audioStart = reaction( @@ -183,27 +156,18 @@ export class AudioBox extends ViewBoxAnnotatableComponent { - let link = false; - !Doc.AreProtosEqual(doc, this.props.Document) && this.links.forEach(l => { - if (l.anchor1 === doc || l.anchor2 === doc) { - const { la1, la2, linkTime } = this.getLinkData(l); - let startTime = linkTime; - if (la2.audioStart) startTime = NumCast(la2.audioStart); - if (la1.audioStart) startTime = NumCast(la1.audioStart); - - let endTime; - if (la1.audioEnd) endTime = NumCast(la1.audioEnd); - if (la2.audioEnd) endTime = NumCast(la2.audioEnd); - - if (startTime) { - link = true; - this.layoutDoc.playOnSelect && (endTime ? this.playFrom(startTime, endTime) : this.playFrom(startTime)); - } + console.log(doc); + this.links.filter(l => l.anchor1 === doc || l.anchor2 === doc).forEach(l => { + const { la1, la2 } = this.getLinkData(l); + const startTime = NumCast(la1.audioStart, NumCast(la2.audioStart, null)); + const endTime = NumCast(la1.audioEnd, NumCast(la2.audioEnd, null)); + if (startTime !== undefined) { + this.layoutDoc.playOnSelect && (endTime ? this.playFrom(startTime, endTime) : this.playFrom(startTime)); } }); - - this.layoutDoc.playOnSelect && Doc.AreProtosEqual(doc, this.props.Document) && this.pause(); - return link; + if (doc.annotationOn === this.rootDoc) { + this.playFrom(NumCast(doc.audioStart), Cast(doc.audioEnd, "number", null)); + } } // for updating the timecode @@ -227,7 +191,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent { this.recordingStart && this.playFrom((absoluteTime - this.recordingStart) / 1000); } @@ -292,7 +256,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent { const [{ result }] = await Networking.UploadFilesToServer(e.data); if (!(result instanceof Error)) { @@ -315,14 +279,14 @@ export class AudioBox extends ViewBoxAnnotatableComponent { this._recorder.stop(); this._recorder = undefined; this.dataDoc.duration = (new Date().getTime() - this._recordStart - this.pauseTime) / 1000; this.audioState = "paused"; this._stream?.getAudioTracks()[0].stop(); - const ind = DocUtils.ActiveRecordings.indexOf(this.props.Document); + const ind = DocUtils.ActiveRecordings.indexOf(this); ind !== -1 && (DocUtils.ActiveRecordings.splice(ind, 1)); }); @@ -413,7 +377,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent screen_delta / rect.width * this.audioDuration; this._markerStart = this._markerEnd = toTimeline(e.clientX - rect.x); setupMoveUpEvents(this, e, @@ -568,7 +532,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent AudioBox.RangePlayScript; labelPlayScript = () => AudioBox.LabelPlayScript; renderInner = computedFn(function (this: AudioBox, mark: Doc, script: undefined | (() => ScriptField), doublescript: undefined | (() => ScriptField), x: number, y: number, width: number, height: number) { - let marker = observable({ view: undefined as any }); + const marker = observable({ view: undefined as any }); return { marker, view: marker.view = r)} Document={mark} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 98995d040..131e33e2a 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -52,7 +52,7 @@ export interface DocumentViewSharedProps { fitContentsToDoc?: boolean; // used by freeformview to fit its contents to its panel. corresponds to _fitToBox property on a Document ContainingCollectionView: Opt; ContainingCollectionDoc: Opt; - setContentView?: (view: { getAnchor: () => Doc }) => any, + setContentView?: (view: { getAnchor: () => Doc }) => any; CollectionFreeFormDocumentView?: () => CollectionFreeFormDocumentView; PanelWidth: () => number; PanelHeight: () => number; @@ -553,7 +553,7 @@ export class DocumentViewInternal extends DocComponent this.props.ScreenToLocalTransform().translate(0, -this.headerMargin); contentScaling = () => this.ContentScale; onClickFunc = () => this.onClickHandler; - makeLink = () => this.props.DocumentView._link; // pass the link placeholde to child views so they can react to make a specialized anchor. This is essentially a function call to the descendants since the value of the _link variable will immediately get set back to undefined. + makeLink = () => this.props.DocumentView.LinkBeingCreated; // pass the link placeholde to child views so they can react to make a specialized anchor. This is essentially a function call to the descendants since the value of the _link variable will immediately get set back to undefined. setContentView = (view: { getAnchor: () => Doc }) => this._componentView = view; @observable contentsActive: () => boolean = returnFalse; @action setContentsActive = (setActive: () => boolean) => this.contentsActive = setActive; @@ -722,15 +722,6 @@ export class DocumentViewInternal extends DocComponent; } - // used to decide whether a link anchor view should be created or not. - // if it's a temporal link (currently just for Audio), then the audioBox will display the anchor and we don't want to display it here. - // would be good to generalize this some way. - isNonTemporalLink = (linkDoc: Doc) => { - const anchor = Cast(Doc.AreProtosEqual(this.props.Document, Cast(linkDoc.anchor1, Doc) as Doc) ? linkDoc.anchor1 : linkDoc.anchor2, Doc) as Doc; - const ept = Doc.AreProtosEqual(this.props.Document, Cast(linkDoc.anchor1, Doc) as Doc) ? linkDoc.anchor1_timecode : linkDoc.anchor2_timecode; - return anchor.type === DocumentType.AUDIO && NumCast(ept) ? false : true; - } - @undoBatch hideLinkAnchor = (doc: Doc | Doc[]) => (doc instanceof Doc ? [doc] : doc).reduce((flg, doc) => flg && (doc.hidden = true), true) anchorPanelWidth = () => this.props.PanelWidth() || 1; @@ -745,7 +736,7 @@ export class DocumentViewInternal extends DocComponent !d.hidden && this.isNonTemporalLink(d)); + const filtered = DocUtils.FilterDocs(this.directLinks, this.props.docFilters(), []).filter(d => !d.hidden); return filtered.map((d, i) =>
{ let la1 = l.anchor1 as Doc; let la2 = l.anchor2 as Doc; - this._linkTime = NumCast(l.anchor2_timecode); + this._linkTime = NumCast(la1.audioStart, NumCast(la2.audioStart)); audioState = la2.audioState; if (Doc.AreProtosEqual(la2, this.dataDoc)) { la1 = l.anchor2 as Doc; la2 = l.anchor1 as Doc; - this._linkTime = NumCast(l.anchor1_timecode); audioState = la1.audioState; } }); -- cgit v1.2.3-70-g09d2 From ba3bcbbf3f0ce8769acb6e84ac3aa8ac3a5c9694 Mon Sep 17 00:00:00 2001 From: bobzel Date: Fri, 15 Jan 2021 15:27:16 -0500 Subject: fixed more issues with audio Box - simplified decorations when selected. fixed dragging when not selected. added esc to stop dragging. --- src/client/views/DocumentDecorations.tsx | 54 ++++++------ src/client/views/GlobalKeyHandler.ts | 4 + src/client/views/InkStrokeProperties.ts | 2 +- src/client/views/collections/TreeView.tsx | 5 +- src/client/views/nodes/AudioBox.scss | 1 - src/client/views/nodes/AudioBox.tsx | 140 +++++++++++------------------- src/client/views/nodes/DocumentView.tsx | 2 +- 7 files changed, 91 insertions(+), 117 deletions(-) (limited to 'src') diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index c2de78d09..e1b9fe8aa 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -569,7 +569,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
); - const openIcon = !canOpen ? (null) : Open in Tab (ctrl: as alias, shift: in new collection)
} placement="top">
{ e.preventDefault(); e.stopPropagation(); }} onPointerDown={this.onMaximizeDown}> + const openIcon = !canOpen ? (null) : Open in Tab (ctrl: as alias, shift: in new collection)
} placement="top">
{ e.preventDefault(); e.stopPropagation(); }} onPointerDown={this.onMaximizeDown}> {SelectionManager.Views().length === 1 ? : "..."}
; @@ -613,31 +613,35 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b }}> {closeIcon} {bounds.r - bounds.x < 100 ? null : titleArea} - {SelectionManager.Views().length !== 1 || seldoc.Document.type === DocumentType.INK ? (null) : - {`${seldoc.finalLayoutKey.includes("icon") ? "De" : ""}Iconify Document`}
} placement="top"> -
- -
- } - {openIcon} -
e.preventDefault()} /> -
e.preventDefault()} /> -
e.preventDefault()} /> -
e.preventDefault()} /> -
-
e.preventDefault()} /> -
e.preventDefault()} /> -
e.preventDefault()} /> -
e.preventDefault()} /> - {seldoc.props.renderDepth <= 1 || !seldoc.props.ContainingCollectionView ? (null) : - tap to select containing document
} placement="top"> -
e.preventDefault()}> - -
} -
+ {SelectionManager.Views().length !== 1 || seldoc.Document.type === DocumentType.INK ? (null) : + {`${seldoc.finalLayoutKey.includes("icon") ? "De" : ""}Iconify Document`}
} placement="top"> +
+ +
+ } + {openIcon} +
e.preventDefault()} /> +
e.preventDefault()} /> +
e.preventDefault()} /> +
e.preventDefault()} /> +
+
e.preventDefault()} /> +
e.preventDefault()} /> +
e.preventDefault()} /> +
e.preventDefault()} /> + + {seldoc.props.renderDepth <= 1 || !seldoc.props.ContainingCollectionView ? (null) : + tap to select containing document
} placement="top"> +
e.preventDefault()}> + +
} + + } +
e.preventDefault()}>{useRotation && "⟲"}
-
{seldoc?.Document.type === DocumentType.FONTICON ? (null) :
diff --git a/src/client/views/GlobalKeyHandler.ts b/src/client/views/GlobalKeyHandler.ts index c38842c4f..8a07c5321 100644 --- a/src/client/views/GlobalKeyHandler.ts +++ b/src/client/views/GlobalKeyHandler.ts @@ -27,6 +27,7 @@ import { SnappingManager } from "../util/SnappingManager"; import { SearchBox } from "./search/SearchBox"; import { random } from "lodash"; import { DocumentView } from "./nodes/DocumentView"; +import { AudioBox } from "./nodes/AudioBox"; const modifiers = ["control", "meta", "shift", "alt"]; type KeyHandler = (keycode: string, e: KeyboardEvent) => KeyControlInfo | Promise; @@ -121,6 +122,9 @@ export class KeyManager { DragManager.AbortDrag(); } else if (CollectionDockingView.Instance.HasFullScreen) { CollectionDockingView.Instance.CloseFullScreen(); + } else if (AudioBox.SelectingRegion) { + AudioBox.SelectingRegion = undefined; + doDeselect = false; } else { doDeselect = !ContextMenu.Instance.closeMenu(); } diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index fcc6b9da0..ce7f3d8d9 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -220,7 +220,7 @@ export class InkStrokeProperties { ((ink[0].X === ink[ink.length - 1].X) && (ink[0].Y === ink[ink.length - 1].Y) && (i === 0 || i === ink.length - 1) && (controlNum === 0 || controlNum === ink.length - 1)) ) ? { X: ink[i].X - xDiff, Y: ink[i].Y - yDiff } : - { X: ink[i].X, Y: ink[i].Y }) + { X: ink[i].X, Y: ink[i].Y }); } const oldx = doc.x; const oldy = doc.y; diff --git a/src/client/views/collections/TreeView.tsx b/src/client/views/collections/TreeView.tsx index a61a9e43c..c4934cf45 100644 --- a/src/client/views/collections/TreeView.tsx +++ b/src/client/views/collections/TreeView.tsx @@ -379,7 +379,8 @@ export class TreeView extends React.Component { TraceMobx(); const expandKey = this.treeViewExpandedView; if (["links", "annotations", this.fieldKey].includes(expandKey)) { - const remDoc = (doc: Doc | Doc[]) => this.remove(doc, expandKey); + const key = expandKey === "annotations" ? this.fieldKey + "-annotations" : expandKey; + const remDoc = (doc: Doc | Doc[]) => this.remove(doc, key); const localAdd = (doc: Doc, addBefore?: Doc, before?: boolean) => { // if there's a sort ordering specified that can be modified on drop (eg, zorder can be modified, alphabetical can't), // then the modification would be done here @@ -391,7 +392,7 @@ export class TreeView extends React.Component { docs.sort((a, b) => NumCast(a.zIndex) > NumCast(b.zIndex) ? 1 : -1); docs.forEach((d, i) => d.zIndex = i); } - const added = Doc.AddDocToList(this.dataDoc, expandKey, doc, addBefore, before, false, true); + const added = Doc.AddDocToList(this.dataDoc, key, doc, addBefore, before, false, true); added && (doc.context = this.doc.context); return added; }; diff --git a/src/client/views/nodes/AudioBox.scss b/src/client/views/nodes/AudioBox.scss index 36cc22d79..93cdbbb09 100644 --- a/src/client/views/nodes/AudioBox.scss +++ b/src/client/views/nodes/AudioBox.scss @@ -4,7 +4,6 @@ height: 100%; position: inherit; display: flex; - pointer-events: all; position: relative; cursor: default; diff --git a/src/client/views/nodes/AudioBox.tsx b/src/client/views/nodes/AudioBox.tsx index 9f8bdcd57..c3c876b75 100644 --- a/src/client/views/nodes/AudioBox.tsx +++ b/src/client/views/nodes/AudioBox.tsx @@ -3,17 +3,17 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import axios from "axios"; import { action, computed, IReactionDisposer, observable, reaction, runInAction } from "mobx"; import { observer } from "mobx-react"; +import { computedFn } from "mobx-utils"; import Waveform from "react-audio-waveform"; import { DateField } from "../../../fields/DateField"; import { Doc, DocListCast, Opt } from "../../../fields/Doc"; import { documentSchema } from "../../../fields/documentSchemas"; -import { Id } from "../../../fields/FieldSymbols"; import { List } from "../../../fields/List"; import { createSchema, listSpec, makeInterface } from "../../../fields/Schema"; import { ComputedField, ScriptField } from "../../../fields/ScriptField"; -import { Cast, DateCast, NumCast } from "../../../fields/Types"; +import { Cast, NumCast } from "../../../fields/Types"; import { AudioField, nullAudio } from "../../../fields/URLField"; -import { emptyFunction, formatTime, numberRange, returnFalse, returnTrue, setupMoveUpEvents, Utils } from "../../../Utils"; +import { emptyFunction, formatTime, numberRange, returnFalse, setupMoveUpEvents, Utils } from "../../../Utils"; import { Docs, DocUtils } from "../../documents/Documents"; import { Networking } from "../../Network"; import { CurrentUserUtils } from "../../util/CurrentUserUtils"; @@ -29,7 +29,6 @@ import { DocumentView } from "./DocumentView"; import { FieldView, FieldViewProps } from './FieldView'; import { FormattedTextBoxComment } from "./formattedText/FormattedTextBoxComment"; import { LinkDocPreview } from "./LinkDocPreview"; -import { computedFn } from "mobx-utils"; declare class MediaRecorder { // whatever MediaRecorder has @@ -47,7 +46,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent = []; _audioRef = React.createRef(); _timeline: Opt; - _duration = 0; _markerStart: number = 0; _currMarker: any; - @observable _selectRegionVisible: boolean = false; + @observable static SelectingRegion: AudioBox | undefined = undefined; + @observable static _scrubTime = 0; @observable _markerEnd: number = 0; @observable _position: number = 0; @observable _waveHeight: Opt = this.layoutDoc._height; - @observable private _paused: boolean = false; - @observable private static _scrubTime = 0; + @observable _paused: boolean = false; @computed get audioState(): undefined | "recording" | "paused" | "playing" { return this.dataDoc.audioState as (undefined | "recording" | "paused" | "playing"); } set audioState(value) { this.dataDoc.audioState = value; } public static SetScrubTime = action((timeInMillisFrom1970: number) => { AudioBox._scrubTime = 0; AudioBox._scrubTime = timeInMillisFrom1970; }); @computed get recordingStart() { return Cast(this.dataDoc[this.props.fieldKey + "-recordingStart"], DateField)?.date.getTime(); } @computed get audioDuration() { return NumCast(this.dataDoc.duration); } - async slideTemplate() { return (await Cast((await Cast(Doc.UserDoc().slidesBtn, Doc) as Doc).dragFactory, Doc) as Doc); } + @computed get markerDocs() { return DocListCast(this.dataDoc[this.annotationKey]); } + @computed get links() { return DocListCast(this.dataDoc.links); } + @computed get pauseTime() { return this._pauseEnd - this._pauseStart; } // total time paused to update the correct time constructor(props: Readonly) { super(props); @@ -103,7 +99,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent { - const time = this._ele?.currentTime || Cast(this.props.Document._currentTimecode, "number", null) || (this.audioState === "recording" ? (Date.now() - (this.recordingStart || 0)) / 1000 : undefined); - return time ? this.createMarker(time) : this.rootDoc; + 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() { - if (!this.dataDoc.markerAmount) { - this.dataDoc.markerAmount = 0; - } 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.audioState = this.path ? "paused" : undefined; @@ -156,7 +148,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent { - console.log(doc); this.links.filter(l => l.anchor1 === doc || l.anchor2 === doc).forEach(l => { const { la1, la2 } = this.getLinkData(l); const startTime = NumCast(la1.audioStart, NumCast(la2.audioStart, null)); @@ -165,9 +156,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent { clearTimeout(this._play); - this._duration = endTime - seekTimeInSeconds; if (Number.isNaN(this._ele?.duration)) { setTimeout(() => this.playFrom(seekTimeInSeconds, endTime), 500); } else if (this._ele && AudioBox.Enabled) { @@ -231,7 +219,7 @@ export class AudioBox extends ViewBoxAnnotatableComponent this.audioState = "playing"); if (endTime !== this.audioDuration) { - this._play = setTimeout(() => this.pause(), (this._duration) * 1000); // use setTimeout to play a specific duration + this._play = setTimeout(() => this.pause(), (endTime - seekTimeInSeconds) * 1000); // use setTimeout to play a specific duration } } else { this.pause(); @@ -350,7 +338,6 @@ export class AudioBox extends ViewBoxAnnotatableComponent { const rect = this._timeline?.getBoundingClientRect();// (e.target as any).getBoundingClientRect(); - if (rect && e.target !== this._audioRef.current) { + if (rect && e.target !== this._audioRef.current && this.active()) { const wasPaused = this.audioState === "paused"; this._ele!.currentTime = this.layoutDoc._currentTimecode = (e.clientX - rect.x) / rect.width * this.audioDuration; wasPaused && this.pause(); - this.props.select(false); const toTimeline = (screen_delta: number) => screen_delta / rect.width * this.audioDuration; this._markerStart = this._markerEnd = toTimeline(e.clientX - rect.x); + AudioBox.SelectingRegion = this; setupMoveUpEvents(this, e, action(e => { - this._selectRegionVisible = true; this._markerEnd = toTimeline(e.clientX - rect.x); if (this._markerEnd < this._markerStart) { const tmp = this._markerStart; @@ -392,16 +372,20 @@ export class AudioBox extends ViewBoxAnnotatableComponent { - (Math.abs(movement[0]) > 15) && this.createMarker(this._markerStart, toTimeline(e.clientX - rect.x)); - this._selectRegionVisible = false; + AudioBox.SelectingRegion === this && (Math.abs(movement[0]) > 15) && this.createMarker(this._markerStart, toTimeline(e.clientX - rect.x)); + AudioBox.SelectingRegion = undefined; }), - e => e.shiftKey && this.createMarker(this._ele!.currentTime) - ); + e => { + this.props.select(false); + e.shiftKey && this.createMarker(this._ele!.currentTime); + } + , this.props.isSelected(true) || this._isChildActive); } } @action - createMarker(audioStart: number, audioEnd?: number) { + createMarker(audioStart?: number, audioEnd?: number) { + if (audioStart === undefined) return this.rootDoc; const marker = Docs.Create.LabelDocument({ title: ComputedField.MakeFunction(`"#" + formatToTime(self.audioStart) + "-" + formatToTime(self.audioEnd)`) as any, useLinkSmallAnchor: true, hideLinkButton: true, audioStart, audioEnd, _showSidebar: false, @@ -448,56 +432,35 @@ export class AudioBox extends ViewBoxAnnotatableComponent { - const increment = this.audioDuration / AudioBox.NUMBER_OF_BUCKETS; - this._count = []; - for (let i = 0; i < AudioBox.NUMBER_OF_BUCKETS; i++) { - this._count.push([increment * i, 0]); - } - } - // makes sure no markers overlaps each other by setting the correct position and width - isOverlap = (m: any) => { - if (this._first) { - this._first = false; - this.markers(); - } - let max = 0; + getLevel = (m: any, placed: { audioStart: number, audioEnd: number, level: number }[]) => { const timelineContentWidth = this.props.PanelWidth() - AudioBox.playheadWidth; - const audioEnd = m.audioEnd === undefined ? m.audioStart + 10 / timelineContentWidth * this.audioDuration : m.audioEnd; - for (let i = 0; i < AudioBox.NUMBER_OF_BUCKETS; i++) { - if (this._count[i][0] >= m.audioStart && this._count[i][0] <= audioEnd) { - this._count[i][1]++; - - if (this._count[i][1] > max) { - max = this._count[i][1]; - } - } - } - - for (let i = 0; i < AudioBox.NUMBER_OF_BUCKETS; i++) { - if (this._count[i][0] >= m.audioStart && this._count[i][0] <= audioEnd) { - this._count[i][1] = max; + const x1 = m.audioStart; + const x2 = m.audioEnd === undefined ? m.audioStart + 10 / timelineContentWidth * this.audioDuration : m.audioEnd; + let max = 0; + const overlappedLevels = new Set(placed.map(p => { + const y1 = p.audioStart; + const y2 = p.audioEnd; + if ((x1 >= y1 && x1 <= y2) || (x2 >= y1 && x2 <= y2) || + (y1 >= x1 && y1 <= x2) || (y2 >= x1 && y2 <= x2)) { + max = Math.max(max, p.level); + return p.level; } - } + })); + let level = max + 1; + for (let j = max; j >= 0; j--) !overlappedLevels.has(j) && (level = j); - if (this.dataDoc.markerAmount < max) { - this.dataDoc.markerAmount = max; - } - return max - 1; + placed.push({ audioStart: x1, audioEnd: x2, level }); + return level; } @computed get selectionContainer() { - return !this._selectRegionVisible ? (null) :
; } - @computed get markerDocs() { return DocListCast(this.dataDoc[this.annotationKey]); } - @computed get links() { return DocListCast(this.dataDoc.links); } - // returns the audio waveform @computed get waveform() { const audioBuckets = Cast(this.dataDoc.audioBuckets, listSpec("number"), []); @@ -544,7 +507,8 @@ export class AudioBox extends ViewBoxAnnotatableComponent this.props.ScreenToLocalTransform().translate(-x - 4, -y - 3)} - parentActive={returnTrue} + 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} ignoreAutoHeight={false} @@ -563,12 +527,14 @@ export class AudioBox extends ViewBoxAnnotatableComponent} ; }); + render() { const interactive = SnappingManager.GetIsDragging() || this.active() ? "-interactive" : ""; - this._first = true; // for indicating the first marker that is rendered - const timelineContentWidth = this.props.PanelWidth() - AudioBox.playheadWidth; const timelineContentHeight = (this.props.PanelHeight() * AudioBox.heightPercent / 100) * AudioBox.heightPercent / 100; // panelHeight * heightPercent is player height. * heightPercent is timeline height (as per css inline) + const overlaps: { audioStart: number, audioEnd: number, level: number }[] = []; + const drawMarkers = this.markerDocs.map((m, i) => ({ level: this.getLevel(m, overlaps), marker: m })); + const maxLevel = overlaps.reduce((m, o) => Math.max(m, o.level), 0) + 1; return
}
: -
+
@@ -603,20 +569,20 @@ export class AudioBox extends ViewBoxAnnotatableComponent {this.waveform}
- {this.markerDocs.map((m, i) => { - const isOverlap = this.isOverlap(m); + {drawMarkers.map((d, i) => { + const m = d.marker; const left = NumCast(m.audioStart) / this.audioDuration * timelineContentWidth; - const top = isOverlap / (this.dataDoc.markerAmount + 1) * timelineContentHeight; + const top = d.level / maxLevel * timelineContentHeight; const timespan = m.audioEnd === undefined ? 10 / timelineContentWidth * this.audioDuration : NumCast(m.audioEnd) - NumCast(m.audioStart); return this.layoutDoc.hideMarkers ? (null) :
{ this.playFrom(NumCast(m.audioStart), Cast(m.audioEnd, "number", null)); e.stopPropagation(); }} > {this.renderMarker(m, this.rangeClickScript, this.rangePlayScript, left + AudioBox.playheadWidth, (1 - AudioBox.heightPercent / 100) / 2 * this.props.PanelHeight() + top, timelineContentWidth * timespan / this.audioDuration, - timelineContentHeight / (this.dataDoc.markerAmount + 1))} + timelineContentHeight / maxLevel)}
; })} {this.selectionContainer} diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 131e33e2a..6371ae5fb 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -416,7 +416,7 @@ export class DocumentViewInternal extends DocComponent { this._timeout = undefined; clickFunc(); }, 500); + this._timeout = setTimeout(() => { this._timeout = undefined; clickFunc(); }, 350); } else clickFunc(); } else if (this.Document["onClick-rawScript"] && !StrCast(Doc.LayoutField(this.layoutDoc))?.includes("ScriptingBox")) {// bcz: hack? don't edit a script if you're clicking on a scripting box itself this.props.addDocTab(DocUtils.makeCustomViewClicked(Doc.MakeAlias(this.props.Document), undefined, "onClick"), "add:right"); -- cgit v1.2.3-70-g09d2 From 46c3885a8c6fee0ed9ac384d0a60716550736970 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 18 Jan 2021 11:12:01 -0500 Subject: fixed marquee dragging in webBox to pick correlate with cursor again. --- src/client/views/nodes/WebBox.tsx | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 7fb14b0cc..876243533 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -484,13 +484,14 @@ export class WebBox extends ViewBoxAnnotatableComponent => { + const scale = this.props.scaling?.() || 1; if (this._savedAnnotations.size() === 0) return undefined; const anno = this._savedAnnotations.values()[0][0]; const annoDoc = Docs.Create.FreeformDocument([], { backgroundColor: color, annotationOn: this.props.Document, title: "Annotation on " + this.Document.title }); - if (anno.style.left) annoDoc.x = parseInt(anno.style.left); - if (anno.style.top) annoDoc.y = NumCast(this.layoutDoc._scrollTop) + parseInt(anno.style.top); - if (anno.style.height) annoDoc._height = parseInt(anno.style.height); - if (anno.style.width) annoDoc._width = parseInt(anno.style.width); + if (anno.style.left) annoDoc.x = parseInt(anno.style.left) / scale; + if (anno.style.top) annoDoc.y = (NumCast(this.layoutDoc._scrollTop) + parseInt(anno.style.top)) / scale; + if (anno.style.height) annoDoc._height = parseInt(anno.style.height) / scale; + if (anno.style.width) annoDoc._width = parseInt(anno.style.width) / scale; anno.remove(); this._savedAnnotations.clear(); return annoDoc; @@ -575,8 +576,8 @@ export class WebBox extends ViewBoxAnnotatableComponent
- {this.props.isSelected() ? this.editToggleBtn() : null}
); } -- cgit v1.2.3-70-g09d2 From c94a8d93ea7373af54355b5c47bf14a021cf4563 Mon Sep 17 00:00:00 2001 From: bobzel Date: Mon, 18 Jan 2021 11:29:43 -0500 Subject: fixed creating right margins for WebBox's --- src/client/views/nodes/WebBox.tsx | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'src') diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx index 876243533..4c4f3f15a 100644 --- a/src/client/views/nodes/WebBox.tsx +++ b/src/client/views/nodes/WebBox.tsx @@ -458,7 +458,7 @@ export class WebBox extends ViewBoxAnnotatableComponent