diff options
Diffstat (limited to 'src/client/views/nodes')
| -rw-r--r-- | src/client/views/nodes/CollectionFreeFormDocumentView.tsx | 52 | ||||
| -rw-r--r-- | src/client/views/nodes/FieldView.tsx | 1 | ||||
| -rw-r--r-- | src/client/views/nodes/PresBox.scss | 532 | ||||
| -rw-r--r-- | src/client/views/nodes/PresBox.tsx | 765 |
4 files changed, 1267 insertions, 83 deletions
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx index d79e2c9ff..b975e24e2 100644 --- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx +++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx @@ -15,6 +15,9 @@ import { numberRange } from "../../../Utils"; import { ComputedField } from "../../../fields/ScriptField"; import { listSpec } from "../../../fields/Schema"; import { DocumentType } from "../../documents/DocumentTypes"; +import { Zoom, Fade, Flip, Rotate, Bounce, Roll, LightSpeed } from 'react-reveal'; +import { PresBox } from "./PresBox"; + export interface CollectionFreeFormDocumentViewProps extends DocumentViewProps { dataProvider?: (doc: Doc, replica: string) => { x: number, y: number, zIndex?: number, opacity?: number, highlight?: boolean, z: number, transition?: string } | undefined; @@ -112,10 +115,17 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF public static setupKeyframes(docs: Doc[], timecode: number, progressivize: boolean = false) { docs.forEach((doc, i) => { + if (!doc.appearFrame) doc.appearFrame = i; const curTimecode = progressivize ? i : timecode; const xlist = new List<number>(numberRange(timecode + 1).map(i => undefined) as any as number[]); const ylist = new List<number>(numberRange(timecode + 1).map(i => undefined) as any as number[]); const olist = new List<number>(numberRange(timecode + 1).map(t => progressivize && t < i ? 0 : 1)); + const oarray: number[] = []; + console.log(doc.title + "AF: " + doc.appearFrame); + console.log("timecode: " + timecode); + oarray.fill(0, 0, NumCast(doc.appearFrame) - 1); + oarray.fill(1, NumCast(doc.appearFrame), timecode); + console.log(oarray); xlist[curTimecode] = NumCast(doc.x); ylist[curTimecode] = NumCast(doc.y); doc["x-indexed"] = xlist; @@ -134,6 +144,35 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF this.props.Document.y = NumCast(this.props.Document.y) + y; } + @computed get freeformNodeDiv() { + const node = <DocumentView {...this.props} + nudge={this.nudge} + dragDivName={"collectionFreeFormDocumentView-container"} + ContentScaling={this.contentScaling} + ScreenToLocalTransform={this.getTransform} + backgroundColor={this.props.backgroundColor} + opacity={this.opacity} + NativeHeight={this.NativeHeight} + NativeWidth={this.NativeWidth} + PanelWidth={this.panelWidth} + PanelHeight={this.panelHeight} />; + if (this.layoutDoc === PresBox.Instance.childDocs[PresBox.Instance.itemIndex]?.presentationTargetDoc) { + switch (this.layoutDoc.presEffect) { + case "Zoom": return (<Zoom>{node}</Zoom>); break; + case "Fade": return (<Fade>{node}</Fade>); break; + case "Flip": return (<Flip>{node}</Flip>); break; + case "Rotate": return (<Rotate>{node}</Rotate>); break; + case "Bounce": return (<Bounce>{node}</Bounce>); break; + case "Roll": return (<Roll>{node}</Roll>); break; + case "LightSpeed": return (<LightSpeed>{node}</LightSpeed>); break; + case "None": return node; break; + default: return node; break; + } + } else { + return node; + } + } + contentScaling = () => this.nativeWidth > 0 && !this.props.fitToBox && !this.freezeDimensions ? this.width / this.nativeWidth : 1; panelWidth = () => (this.sizeProvider?.width || this.props.PanelWidth?.()); panelHeight = () => (this.sizeProvider?.height || this.props.PanelHeight?.()); @@ -164,6 +203,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF display: this.ZInd === -99 ? "none" : undefined, pointerEvents: this.props.Document.isBackground || this.Opacity === 0 || this.props.Document.type === DocumentType.INK || this.props.Document.isInkMask ? "none" : this.props.pointerEvents ? "all" : undefined }} > + {Doc.UserDoc().renderStyle !== "comic" ? (null) : <div style={{ width: "100%", height: "100%", position: "absolute" }}> <svg style={{ transform: `scale(1,${this.props.PanelHeight() / this.props.PanelWidth()})`, transformOrigin: "top left", overflow: "visible" }} viewBox="0 0 12 14"> @@ -173,17 +213,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF </div>} {!this.props.fitToBox ? - <DocumentView {...this.props} - nudge={this.nudge} - dragDivName={"collectionFreeFormDocumentView-container"} - ContentScaling={this.contentScaling} - ScreenToLocalTransform={this.getTransform} - backgroundColor={this.props.backgroundColor} - opacity={this.opacity} - NativeHeight={this.NativeHeight} - NativeWidth={this.NativeWidth} - PanelWidth={this.panelWidth} - PanelHeight={this.panelHeight} /> + <>{this.freeformNodeDiv}</> : <ContentFittingDocumentView {...this.props} ContainingCollectionDoc={this.props.ContainingCollectionDoc} DataDoc={this.props.DataDoc} diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx index 48e1f6ce3..5d5bc1d73 100644 --- a/src/client/views/nodes/FieldView.tsx +++ b/src/client/views/nodes/FieldView.tsx @@ -45,6 +45,7 @@ export interface FieldViewProps { whenActiveChanged: (isActive: boolean) => void; dontRegisterView?: boolean; focus: (doc: Doc) => void; + presMultiSelect?: (doc: Doc) => void; //added for selecting multiple documents in a presentation ignoreAutoHeight?: boolean; PanelWidth: () => number; PanelHeight: () => number; diff --git a/src/client/views/nodes/PresBox.scss b/src/client/views/nodes/PresBox.scss index 9f6af1bde..bf31f71d2 100644 --- a/src/client/views/nodes/PresBox.scss +++ b/src/client/views/nodes/PresBox.scss @@ -1,5 +1,6 @@ .presBox-cont { position: absolute; + display: block; pointer-events: inherit; z-index: 2; box-shadow: #AAAAAA .2vw .2vw .4vw; @@ -12,73 +13,526 @@ transition: 0.7s opacity ease; .presBox-listCont { - position: absolute; + position: relative; height: calc(100% - 25px); width: 100%; + margin-top: 10px; + } + + .presBox-toolbar { + display: none; } - .presBox-buttons { + .presBox-toolbar.active { + position: relative; + display: inline-flex; + align-items: center; + height: 30px; width: 100%; - background: gray; - padding-top: 5px; - padding-bottom: 5px; - display: grid; - grid-column-end: 4; - grid-column-start: 1; + color: white; + background-color: #323232; - .presBox-viewPicker { - height: 25; + .toolbar-button { + margin-left: 10px; + margin-right: 10px; + letter-spacing: 0; + display: flex; + align-items: center; + transition: 0.5s; + + @media only screen and (max-width: 400) { + .toolbar-buttonText { + display: none; + } + } + } + + .toolbar-button.active { + color: #AEDDF8; + } + + .toolbar-transitionButtons { + display: block; + + .toolbar-transition { + display: flex; + font-size: 10; + width: 100; + background-color: rgba(0, 0, 0, 0); + min-width: max-content; + + .toolbar-icon { + margin-right: 5px; + } + } + } + } + + .toolbar-moreInfo { + position: absolute; + right: 5px; + display: flex; + width: max-content; + height: 25px; + /* background-color: pink; */ + justify-content: center; + transform: rotate(90deg); + align-items: center; + transition: 0.7s ease; + + .toolbar-moreInfoBall { + width: 4px; + height: 4px; + border-radius: 100%; + background-color: white; + margin: 1px; position: relative; - display: inline-block; - grid-column: 1/2; - min-width: 15px; } + } - select { - background: #323232; + .toolbar-moreInfo.active { + transform: rotate(0deg); + } + + .toolbar-divider { + border-left: solid #ffffff70 0.5px; + height: 20px; + } +} + +.dropdown { + font-size: 10; + margin-left: 5px; + color: darkgrey; + transition: 0.5s ease; +} + +.dropdown.active { + transform: rotate(180deg); + color: #AEDDF8; + opacity: 0.8; +} + +.presBox-ribbon { + position: relative; + display: none; + background-color: white; + color: black; + width: 100%; + height: 0; + z-index: 100; + transition: 0.7s; + + .toolbar-slider { + position: relative; + align-self: center; + justify-self: left; + -webkit-appearance: none; + transform: rotateY(180deg); + background-color: #40B3D8; + margin-top: 5px; + width: 100%; + max-width: 120px; + height: 2.5px; + left: 0px; + } + + .toolbar-slider:focus { + outline: none; + } + + .effectDirection { + justify-self: center; + align-self: center; + align-items: center; + justify-content: center; + grid-template-columns: 13px 13px 13px; + display: grid; + } + + .toolbar-slider::-webkit-slider-thumb { + -webkit-appearance: none; + background-color: #40B3D8; + border: 1px white solid; + border-radius: 100%; + width: 9px; + height: 9px; + } + + .slider-headers { + position: relative; + display: grid; + justify-content: space-between; + width: 100%; + height: max-content; + max-width: 120px; + grid-template-columns: auto auto auto; + grid-template-rows: max-content; + font-weight: 100; + /* margin-top: 5px; */ + font-size: 8px; + } + + .slider-value { + top: -20; + color: #2f86a2; + position: absolute; + } + + .slider-value.none, + .slider-headers.none, + .toolbar-slider.none { + display: none; + } + + .dropdown-header { + padding-bottom: 10px; + font-weight: 800; + text-align: center; + font-size: 16; + width: 90%; + color: black; + transform: translate(5%, 0px); + border-bottom: solid 2px darkgrey; + } + + + .ribbon-textInput { + border-radius: 2px; + height: 25px; + font-size: 10; + font-weight: 100; + align-self: center; + justify-self: center; + padding-left: 10px; + border: solid 1px black; + width: 100%; + } + + .ribbon-final-box { + align-self: flex-start; + justify-self: center; + display: grid; + grid-template-rows: auto auto; + padding-left: 10px; + padding-right: 10px; + letter-spacing: normal; + min-width: max-content; + width: 100%; + font-size: 13; + font-weight: 600; + position: relative; + + + .ribbon-final-button { + position: relative; + font-size: 10; + font-weight: normal; + letter-spacing: normal; + display: flex; + justify-content: center; + align-items: center; + margin-bottom: 5px; + height: 25px; color: white; + width: 100%; + max-width: 120; + padding-left: 10; + padding-right: 10; + border-radius: 10px; + background-color: #979797; } - .presBox-button { - margin-right: 2.5%; - margin-left: 2.5%; - height: 25px; - border-radius: 5px; + .ribbon-final-button-hidden { + position: relative; + font-size: 10; + font-weight: normal; + letter-spacing: normal; display: flex; + justify-content: center; align-items: center; - background: #323232; - color: white; + margin-bottom: 5px; + height: 25px; + color: lightgrey; + width: 100%; + max-width: 120; + padding-left: 10; + padding-right: 10; + border-radius: 10px; + background-color: black; + } + } + + .selectedList { + display: block; + min-width: 50; + max-width: 120; + height: 70; + overflow-y: scroll; + + .selectedList-items { + font-size: 7; + font-weight: normal; + } + } + + .ribbon-button { + font-size: 10; + font-weight: 200; + height: 25; + border: solid 1px black; + display: flex; + border-radius: 10px; + margin-right: 5px; + width: max-content; + justify-content: center; + align-items: center; + padding-right: 10px; + padding-left: 10px; + } + + .ribbon-button.active { + background-color: #5B9FDD; + } + + .ribbon-button:hover { + background-color: lightgrey; + } + + svg.svg-inline--fa.fa-thumbtack.fa-w-12.toolbar-thumbtack { + right: 40; + position: absolute; + transform: rotate(45deg); + } + + .ribbon-box { + display: grid; + grid-template-rows: max-content auto; + justify-self: center; + padding-left: 10px; + padding-right: 10px; + letter-spacing: normal; + width: 100%; + font-weight: 600; + position: relative; + font-size: 13; + border-right: solid 2px darkgrey; + + .presBox-dropdown:hover { + border: solid 1px #378AD8; - svg { - margin: auto; + .presBox-dropdownOption { + font-size: 10; + display: block; + padding-left: 5px; + padding-right: 5px; + margin-top: 3; + margin-bottom: 3; + } + + .presBox-dropdownOption:hover { + position: relative; + background-color: lightgrey; + } + + .presBox-dropdownOption.active { + position: relative; + background-color: #9CE2F8; + } + + .presBox-dropdownOptions { + position: absolute; + top: 19px; + left: -1px; + z-index: 200; + width: 85%; + min-width: max-content; + display: block; + background: #FFFFFF; + border: 0.5px solid #979797; + box-sizing: border-box; + box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25); + } + + .presBox-dropdownIcon { + color: #378AD8; } } - .collectionViewBaseChrome-viewPicker { - min-width: 50; - width: 5%; - height: 25; + .presBox-dropdown { + display: grid; + grid-template-columns: auto 20%; position: relative; - display: inline-block; + border: solid 1px black; + font-size: 10; + height: 20; + padding-left: 5px; + align-items: center; + margin-top: 5px; + margin-bottom: 5px; + font-weight: 200; + width: 100%; + min-width: max-content; + max-width: 120; + overflow: visible; + + .presBox-dropdownOptions { + display: none; + } + + .presBox-dropdownIcon { + position: relative; + color: black; + align-self: center; + justify-self: center; + margin-right: 2px; + } } } +} - .presBox-backward, - .presBox-forward { - width: 25px; - border-radius: 5px; - top: 50%; - position: absolute; +.presBox-ribbon.active { + display: grid; + grid-template-columns: auto auto auto auto auto; + grid-template-rows: 100%; + height: 100px; + padding-top: 5px; + padding-bottom: 5px; + border: solid 1px black; + + ::-webkit-scrollbar { + -webkit-appearance: none; + height: 3px; + width: 8px; + } + + ::-webkit-scrollbar-thumb { + border-radius: 2px; + background-color: rgb(101, 164, 220); + } +} + +.dropdown-play-button { + font-size: 10; + margin-left: 10; + margin-right: 10; + padding-top: 5px; + padding-bottom: 5px; + text-align: left; + justify-content: left; + border-bottom: solid 1px lightgrey; +} + +.dropdown-play { + top: 32px; + display: none; + border-radius: 5px; + width: max-content; + min-height: 20px; + height: max-content; + z-index: 200; + background-color: #323232; + position: absolute; +} + +.dropdown-play.active { + display: block; +} + +.presBox-buttons { + position: relative; + width: 100%; + background: gray; + padding-top: 5px; + padding-bottom: 5px; + display: grid; + grid-template-columns: auto auto; + + .presBox-viewPicker { + height: 25; + position: relative; display: inline-block; + grid-column: 1; + border-radius: 5px; + min-width: 15px; + max-width: 100px; + } + + .presBox-presentPanel { + display: flex; + justify-self: end; + width: 100%; + + } + + select { + background: #323232; + color: white; } - .presBox-backward { - left: 5; + .presBox-button { + margin-right: 2.5px; + margin-left: 2.5px; + height: 25px; + border-radius: 5px; + display: none; + justify-content: center; + align-content: center; + align-items: center; + text-align: center; + letter-spacing: normal; + width: inherit; + background: #323232; + color: white; } - .presBox-forward { - right: 5; + .presBox-button.active { + display: flex; } + + .presBox-button.edit { + display: flex; + max-width: 25px; + } + + .presBox-button.present { + display: flex; + min-width: 100px; + width: 100px; + position: absolute; + right: 0px; + + .present-icon { + margin-right: 7px; + } + } + + + + .collectionViewBaseChrome-viewPicker { + min-width: 50; + width: 5%; + height: 25; + position: relative; + display: inline-block; + } +} + +.presBox-backward, +.presBox-forward { + width: 25px; + border-radius: 5px; + top: 50%; + position: absolute; + display: inline-block; +} + +.presBox-backward { + left: 5; +} + +.presBox-forward { + right: 5; } // CSS adjusted for mobile devices diff --git a/src/client/views/nodes/PresBox.tsx b/src/client/views/nodes/PresBox.tsx index 8818d375e..fc5e73c81 100644 --- a/src/client/views/nodes/PresBox.tsx +++ b/src/client/views/nodes/PresBox.tsx @@ -9,17 +9,23 @@ import { returnFalse, returnOne } from "../../../Utils"; import { documentSchema } from "../../../fields/documentSchemas"; import { DocumentManager } from "../../util/DocumentManager"; import { undoBatch } from "../../util/UndoManager"; -import { CollectionDockingView } from "../collections/CollectionDockingView"; +import { CollectionDockingView, DockedFrameRenderer } from "../collections/CollectionDockingView"; import { CollectionView, CollectionViewType } from "../collections/CollectionView"; import { FieldView, FieldViewProps } from './FieldView'; import "./PresBox.scss"; import { ViewBoxBaseComponent } from "../DocComponent"; -import { makeInterface } from "../../../fields/Schema"; +import { makeInterface, listSpec } from "../../../fields/Schema"; import { Docs } from "../../documents/Documents"; import { PrefetchProxy } from "../../../fields/Proxy"; import { ScriptField } from "../../../fields/ScriptField"; import { Scripting } from "../../util/Scripting"; import { InkingStroke } from "../InkingStroke"; +import { HighlightSpanKind } from "typescript"; +import { SearchUtil } from "../../util/SearchUtil"; +import { CollectionFreeFormDocumentView } from "./CollectionFreeFormDocumentView"; +import { child } from "serializr"; +import { Zoom, Fade, Flip, Rotate, Bounce, Roll, LightSpeed } from 'react-reveal'; + type PresBoxSchema = makeInterface<[typeof documentSchema]>; const PresBoxDocument = makeInterface(documentSchema); @@ -27,15 +33,17 @@ const PresBoxDocument = makeInterface(documentSchema); @observer export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema>(PresBoxDocument) { public static LayoutString(fieldKey: string) { return FieldView.LayoutString(PresBox, fieldKey); } + static Instance: PresBox; @observable _isChildActive = false; @computed get childDocs() { return DocListCast(this.dataDoc[this.fieldKey]); } @computed get itemIndex() { return NumCast(this.rootDoc._itemIndex); } @computed get presElement() { return Cast(Doc.UserDoc().presElement, Doc, null); } constructor(props: any) { super(props); + PresBox.Instance = this; if (!this.presElement) { // create exactly one presElmentBox template to use by any and all presentations. Doc.UserDoc().presElement = new PrefetchProxy(Docs.Create.PresElementBoxDocument({ - title: "pres element template", backgroundColor: "transparent", _xMargin: 5, _height: 46, isTemplateDoc: true, isTemplateForField: "data" + title: "pres element template", backgroundColor: "transparent", _xMargin: 0, isTemplateDoc: true, isTemplateForField: "data" })); // this script will be called by each presElement to get rendering-specific info that the PresBox knows about but which isn't written to the PresElement // this is a design choice -- we could write this data to the presElements which would require a reaction to keep it up to date, and it would prevent @@ -51,7 +59,14 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> this.rootDoc.presBox = this.rootDoc; this.rootDoc._forceRenderEngine = "timeline"; this.rootDoc._replacedChrome = "replaced"; + this.layoutDoc.presStatus = "edit"; + document.addEventListener("keydown", this.keyEvents, false); + } + + componentWillUnmount() { + document.removeEventListener("keydown", this.keyEvents, false); } + updateCurrentPresentation = () => Doc.UserDoc().activePresentation = this.rootDoc; @undoBatch @@ -146,7 +161,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> /** * This method makes sure that cursor navigates to the element that * has the option open and last in the group. If not in the group, and it has - * te option open, navigates to that element. + * the option open, navigates to that element. */ navigateToElement = async (curDoc: Doc, fromDocIndex: number) => { this.updateCurrentPresentation(); @@ -201,31 +216,59 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> if (index >= 0 && index < this.childDocs.length) { this.rootDoc._itemIndex = index; const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null); - if (presTargetDoc.lastFrame !== undefined) { + if (presTargetDoc?.lastFrame !== undefined) { presTargetDoc.currentFrame = 0; } - - if (!this.layoutDoc.presStatus) { - this.layoutDoc.presStatus = true; - this.startPresentation(index); - } - + // if (this.layoutDoc.presStatus === "edit") { + // this.layoutDoc.presStatus = true; + // this.startPresentation(index); + // } this.navigateToElement(this.childDocs[index], fromDoc); this.hideIfNotPresented(index); this.showAfterPresented(index); + this.onHideDocumentUntilPressClick(); } }); + + @observable _presTimer!: NodeJS.Timeout; + //The function that starts or resets presentaton functionally, depending on status flag. - startOrResetPres = () => { + @action + startOrResetPres = (startSlide: number) => { this.updateCurrentPresentation(); - if (this.layoutDoc.presStatus) { - this.resetPresentation(); + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); + if (this._presTimer && this.layoutDoc.presStatus === "auto") { + clearInterval(this._presTimer); + this.layoutDoc.presStatus = "manual"; } else { - this.layoutDoc.presStatus = true; - this.startPresentation(0); - this.gotoDocument(0, this.itemIndex); + this.layoutDoc.presStatus = "auto"; + this.startPresentation(startSlide); + this.gotoDocument(startSlide, this.itemIndex); + this._presTimer = setInterval(() => { + if (this.itemIndex + 1 < this.childDocs.length) this.next(); + else { + clearInterval(this._presTimer); + this.layoutDoc.presStatus = "manual"; + } + }, targetDoc.presDuration ? NumCast(targetDoc.presDuration) + NumCast(targetDoc.presTransition) : 2000); + // for (let i = this.itemIndex + 1; i <= this.childDocs.length; i++) { + // if (this.itemIndex + 1 === this.childDocs.length) { + // clearTimeout(this._presTimer); + // this.layoutDoc.presStatus = "manual"; + // } else timer = setTimeout(() => { console.log(i); this.next(); }, i * 2000); + // } + } + + // if (this.layoutDoc.presStatus) { + // this.resetPresentation(); + // } else { + // this.layoutDoc.presStatus = true; + // this.startPresentation(0); + // this.gotoDocument(0, this.itemIndex); + // } } //The function that resets the presentation by removing every action done by it. It also @@ -234,7 +277,7 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> this.updateCurrentPresentation(); this.childDocs.forEach(doc => (doc.presentationTargetDoc as Doc).opacity = 1); this.rootDoc._itemIndex = 0; - this.layoutDoc.presStatus = false; + // this.layoutDoc.presStatus = false; } //The function that starts the presentation, also checking if actions should be applied @@ -279,6 +322,42 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> this.updateMinimize(e, this.rootDoc._viewType = viewType); }); + @undoBatch + movementChanged = action((movement: string) => { + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); + if (movement === 'zoom') { + activeItem.presZoomButton = !activeItem.presZoomButton; + activeItem.presNavButton = false; + } else if (movement === 'nav') { + activeItem.presZoomButton = false; + activeItem.presNavButton = !activeItem.presNavButton; + } else if (movement === 'swap') { + targetDoc.presTransition = 0; + } else { + activeItem.presZoomButton = false; + activeItem.presNavButton = false; + } + }); + + @undoBatch + visibilityChanged = action((visibility: string) => { + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + if (visibility === 'fade') { + activeItem.presFadeButton = !activeItem.presFadeButton; + } else if (visibility === 'hideBefore') { + activeItem.presHideTillShownButton = !activeItem.presHideTillShownButton; + activeItem.presHideAfterButton = false; + } else if (visibility === 'hideAfter') { + activeItem.presHideAfterButton = !activeItem.presHideAfterButton; + activeItem.presHideAfterButton = false; + } else { + activeItem.presHideAfterButton = false; + activeItem.presHideTillShownButton = false; + activeItem.presFadeButton = false; + } + }); + whenActiveChanged = action((isActive: boolean) => this.props.whenActiveChanged(this._isChildActive = isActive)); addDocumentFilter = (doc: Doc | Doc[]) => { const docs = doc instanceof Doc ? [doc] : doc; @@ -290,18 +369,612 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> } childLayoutTemplate = () => this.rootDoc._viewType !== CollectionViewType.Stacking ? undefined : this.presElement; removeDocument = (doc: Doc) => Doc.RemoveDocFromList(this.dataDoc, this.fieldKey, doc); - selectElement = (doc: Doc) => this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.itemIndex)); getTransform = () => this.props.ScreenToLocalTransform().translate(-5, -65);// listBox padding-left and pres-box-cont minHeight panelHeight = () => this.props.PanelHeight() - 20; active = (outsideReaction?: boolean) => ((Doc.GetSelectedTool() === InkTool.None && !this.layoutDoc.isBackground) && (this.layoutDoc.forceActive || this.props.isSelected(outsideReaction) || this._isChildActive || this.props.renderDepth === 0) ? true : false) - render() { - // console.log("render = " + this.layoutDoc.title + " " + this.layoutDoc.presStatus); - // const presOrderedDocs = DocListCast(this.rootDoc.presOrderedDocs); - // if (presOrderedDocs.length != this.childDocs.length || presOrderedDocs.some((pd, i) => pd !== this.childDocs[i])) { - // this.rootDoc.presOrderedDocs = new List<Doc>(this.childDocs.slice()); + + // KEYS + @observable _selectedArray: Doc[] = []; + + @computed get listOfSelected() { + const list = this._selectedArray.map((doc: Doc, index: any) => { + const activeItem = Cast(doc, Doc, null); + const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); + return ( + <div className="selectedList-items">{index + 1}. {targetDoc.title}</div> + ); + }); + return list; + } + + //Regular click + @action + selectElement = (doc: Doc) => { + this._selectedArray = []; + this.gotoDocument(this.childDocs.indexOf(doc), NumCast(this.itemIndex)); + this._selectedArray.push(this.childDocs[this.childDocs.indexOf(doc)]); + console.log(this._selectedArray); + } + + //Command click + @action + multiSelect = (doc: Doc) => { + this._selectedArray.push(this.childDocs[this.childDocs.indexOf(doc)]); + console.log(this._selectedArray); + } + + //Shift click + @action + shiftSelect = (doc: Doc) => { + this._selectedArray = []; + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + if (activeItem) { + for (let i = Math.min(this.itemIndex, this.childDocs.indexOf(doc)); i <= Math.max(this.itemIndex, this.childDocs.indexOf(doc)); i++) { + this._selectedArray.push(this.childDocs[i]); + } + } + console.log(this._selectedArray); + } + + + + //Esc click + @action + keyEvents = (e: KeyboardEvent) => { + e.stopPropagation; + // switch(e.keyCode) { + // case 27: console.log("escape"); + // case 65 && (e.metaKey || e.altKey): // } + // Escape key + if (e.keyCode === 27) { + if (this.layoutDoc.presStatus === "edit") this._selectedArray = []; + else this.layoutDoc.presStatus = "edit"; + // Ctrl-A to select all + } else if ((e.metaKey || e.altKey) && e.keyCode === 65) { + if (this.layoutDoc.presStatus === "edit") this._selectedArray = this.childDocs; + // left / a / up to go back + } else if (e.keyCode === 37 || 65 || 38) { + if (this.layoutDoc.presStatus !== "edit") this.back(); + // right / d / down to go to next + } else if (e.keyCode === 39 || 68 || 40) { + if (this.layoutDoc.presStatus !== "edit") this.next(); + // spacebar to 'present' or go to next slide + } else if (e.keyCode === 32) { + if (this.layoutDoc.presStatus !== "edit") this.next(); + else this.layoutDoc.presStatus = "manual"; + } + } + + @action + onHideDocumentUntilPressClick = () => { + this.childDocs.forEach((doc, index) => { + const curDoc = Cast(doc, Doc, null); + const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null); + if (tagDoc.presEffect === 'None' || !tagDoc.presEffect) { + tagDoc.opacity = 1; + } else { + if (index <= this.itemIndex) { + tagDoc.opacity = 1; + } else { + tagDoc.opacity = 0; + } + } + }); + } + + + @observable private transitionTools: boolean = false; + @observable private newDocumentTools: boolean = false; + @observable private progressivizeTools: boolean = false; + @observable private moreInfoTools: boolean = false; + @observable private playTools: boolean = false; + @observable private pathBoolean: boolean = false; + + // For toggling transition toolbar + @action toggleTransitionTools = () => { + this.transitionTools = !this.transitionTools; + this.newDocumentTools = false; + this.progressivizeTools = false; + this.moreInfoTools = false; + this.playTools = false; + } + // For toggling the add new document dropdown + @action toggleNewDocument = () => { + this.newDocumentTools = !this.newDocumentTools; + this.transitionTools = false; + this.progressivizeTools = false; + this.moreInfoTools = false; + this.playTools = false; + } + // For toggling the tools for progressivize + @action toggleProgressivize = () => { + this.progressivizeTools = !this.progressivizeTools; + this.transitionTools = false; + this.newDocumentTools = false; + this.moreInfoTools = false; + this.playTools = false; + } + // For toggling the tools for more info + @action toggleMoreInfo = () => { + this.moreInfoTools = !this.moreInfoTools; + this.transitionTools = false; + this.newDocumentTools = false; + this.progressivizeTools = false; + this.playTools = false; + } + // For toggling the options when the user wants to select play + @action togglePlay = () => { + this.playTools = !this.playTools; + this.transitionTools = false; + this.newDocumentTools = false; + this.progressivizeTools = false; + this.moreInfoTools = false; + } + + @action toggleAllDropdowns() { + this.transitionTools = false; + this.newDocumentTools = false; + this.progressivizeTools = false; + this.moreInfoTools = false; + this.playTools = false; + } + + @undoBatch + @action + toolbarTest = () => { + const presTargetDoc = Cast(this.childDocs[this.itemIndex].presentationTargetDoc, Doc, null); + console.log("title: " + presTargetDoc.title); + console.log("index: " + this.itemIndex); + } + + @undoBatch + @action + viewPaths = async () => { + const docToJump = this.childDocs[0]; + const aliasOf = await DocCastAsync(docToJump.aliasOf); + const srcContext = aliasOf && await DocCastAsync(aliasOf.context); + if (this.pathBoolean) { + console.log("true"); + if (srcContext) { + this.togglePath(); + srcContext._fitToBox = false; + srcContext._viewType = "freeform"; + srcContext.presPathView = false; + } + } else { + console.log("false"); + if (srcContext) { + this.togglePath(); + srcContext._fitToBox = true; + srcContext._viewType = "freeform"; + srcContext.presPathView = true; + } + } + console.log("view paths"); + const viewType = srcContext?._viewType; + const fit = srcContext?._fitToBox; + + // if (!DocumentManager.Instance.getDocumentView(curPres)) { + // CollectionDockingView.AddRightSplit(curPres); + // } + } + + @computed get paths() { + const paths = []; //List of all of the paths that need to be added + console.log(this.childDocs.length - 1); + for (let i = 0; i <= this.childDocs.length - 1; i++) { + const targetDoc = Cast(this.childDocs[i].presentationTargetDoc, Doc, null); + if (this.childDocs[i + 1] && targetDoc) { + const nextTargetDoc = Cast(this.childDocs[i + 1].presentationTargetDoc, Doc, null); + const n1x = NumCast(targetDoc.x) + (NumCast(targetDoc._width) / 2); + const n1y = NumCast(targetDoc.y) + (NumCast(targetDoc._height) / 2); + const n2x = NumCast(nextTargetDoc.x) + (NumCast(targetDoc._width) / 2); + const n2y = NumCast(nextTargetDoc.y) + (NumCast(targetDoc._height) / 2); + const pathPoints = n1x + "," + n1y + " " + n2x + "," + n2y; + paths.push(<polyline + points={pathPoints} + style={{ + opacity: 0.7, + stroke: "#69a6db", + strokeWidth: 5, + }} + markerStart="url(#square)" + markerEnd="url(#arrow)" />); + } + } + return paths; + } + + @action togglePath = () => this.pathBoolean = !this.pathBoolean; + + /** + * The function that is called on click to turn fading document after presented option on/off. + * It also makes sure that the option swithches from hide-after to this one, since both + * can't coexist. + */ + @action + onFadeDocumentAfterPresentedClick = (e: React.MouseEvent) => { + e.stopPropagation(); + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); + activeItem.presFadeButton = !activeItem.presFadeButton; + if (!activeItem.presFadeButton) { + if (targetDoc) { + targetDoc.opacity = 1; + } + } else { + activeItem.presHideAfterButton = false; + if (this.rootDoc.presStatus !== "edit" && targetDoc) { + targetDoc.opacity = 0.5; + } + } + } + + @action + dropdownToggle = (menu: string) => { + console.log('presBox' + menu + 'Dropdown'); + const dropMenu = document.getElementById('presBox' + menu + 'Dropdown'); + console.log(dropMenu); + console.log(dropMenu?.style.display); + if (dropMenu) dropMenu.style.display === 'none' ? dropMenu.style.display = 'block' : dropMenu.style.display = 'none'; + } + + setTransitionTime = (number: String) => { + const timeInMS = Number(number) * 1000; + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); + if (targetDoc) targetDoc.presTransition = timeInMS; + } + + setDurationTime = (number: String) => { + const timeInMS = Number(number) * 1000; + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); + if (targetDoc) targetDoc.presDuration = timeInMS; + } + + @computed get transitionDropdown() { + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + + if (activeItem) { + const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); + const transitionSpeed = targetDoc.presTransition ? String(Number(targetDoc.presTransition) / 1000) : 0.5; + const duration = targetDoc.presDuration ? String(Number(targetDoc.presDuration) / 1000) : 2; + const transitionThumbLocation = String(-9.48 * Number(transitionSpeed) + 93); + const durationThumbLocation = String(9.48 * Number(duration)); + const movement = activeItem.presZoomButton ? 'Zoom' : activeItem.presNavbutton ? 'Navigate' : 'None'; + const effect = targetDoc.presEffect ? targetDoc.presEffect : 'None'; + const visibility = activeItem.presFadeButton ? 'Fade' : activeItem.presHideTillShownButton ? 'Hide till shown' : activeItem.presHideAfter ? 'Hide on exit' : 'None'; + return ( + <div className={`presBox-ribbon ${this.transitionTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> + <div className="ribbon-box"> + Movement + <div className="presBox-dropdown" + onPointerDown={e => e.stopPropagation()} + // onClick={() => this.dropdownToggle('Movement')} + > + {movement} + <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2 }} icon={"angle-down"} /> + <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onClick={e => e.stopPropagation()}> + <div className={`presBox-dropdownOption ${!activeItem.presZoomButton && !activeItem.presNavButton ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('none')}>None</div> + <div className={`presBox-dropdownOption ${activeItem.presZoomButton ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('zoom')}>Pan and Zoom</div> + <div className={`presBox-dropdownOption ${activeItem.presNavButton ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('nav')}>Pan</div> + <div className={`presBox-dropdownOption ${activeItem.presNavButton ? "active" : ""}`} onPointerDown={e => e.stopPropagation()} onClick={() => this.movementChanged('swap')}>Swap</div> + </div> + </div> + <input type="range" step="0.1" min="0.1" max="10" value={transitionSpeed} className={`toolbar-slider ${activeItem.presZoomButton || activeItem.presNavButton ? "" : "none"}`} id="toolbar-slider" onChange={(e: React.ChangeEvent<HTMLInputElement>) => { e.stopPropagation(); this.setTransitionTime(e.target.value); }} /> + <div className={`slider-headers ${activeItem.presZoomButton || activeItem.presNavButton ? "" : "none"}`}> + <div className={`slider-value ${activeItem.presZoomButton || activeItem.presNavButton ? "" : "none"}`} style={{ left: transitionThumbLocation + '%' }}>{transitionSpeed}s</div> + <div className="slider-text">Slow</div> + <div className="slider-text">Medium</div> + <div className="slider-text">Fast</div> + </div> + </div> + <div className="ribbon-box"> + Duration + <div className="presBox-dropdown" + onPointerDown={e => e.stopPropagation()} + > + {duration} seconds + </div> + <input type="range" step="0.1" min="0.1" max="10" value={duration} style={{ transform: 'rotate(0deg)' }} className={"toolbar-slider"} id="duration-slider" onChange={(e: React.ChangeEvent<HTMLInputElement>) => { e.stopPropagation(); this.setDurationTime(e.target.value); }} /> + <div className={"slider-headers"}> + <div className={"slider-value"} style={{ left: durationThumbLocation + '%' }}>{duration}s</div> + <div className="slider-text">Short</div> + <div className="slider-text"></div> + <div className="slider-text">Long</div> + </div> + {/* <div title="Fade After" className={`ribbon-button ${activeItem.presFadeButton ? "active" : ""}`} onClick={this.onFadeDocumentAfterPresentedClick}>Fade After</div> */} + {/* <div title="Hide After" className={`ribbon-button ${activeItem.presHideTillShownButton ? "active" : ""}`} onClick={() => console.log("hide before")}>Hide Before</div> */} + {/* <div title="Hide Before" className={`ribbon-button ${activeItem.presHideAfterButton ? "active" : ""}`} onClick={() => console.log("hide after")}>Hide After</div> */} + </div> + <div className="ribbon-box"> + Effects + <div className="presBox-dropdown" + onPointerDown={e => e.stopPropagation()} + // onClick={() => this.dropdownToggle('Movement')} + > + {effect} + <FontAwesomeIcon className='presBox-dropdownIcon' style={{ gridColumn: 2 }} icon={"angle-down"} /> + <div className={'presBox-dropdownOptions'} id={'presBoxMovementDropdown'} onClick={e => e.stopPropagation()}> + <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => targetDoc.presEffect = 'None'}>None</div> + <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => targetDoc.presEffect = 'Fade'}>Fade In</div> + <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => targetDoc.presEffect = 'Flip'}>Flip</div> + <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => targetDoc.presEffect = 'Rotate'}>Rotate</div> + <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => targetDoc.presEffect = 'Bounce'}>Bounce</div> + <div className={'presBox-dropdownOption'} onPointerDown={e => e.stopPropagation()} onClick={() => targetDoc.presEffect = 'Roll'}>Roll</div> + </div> + </div> + <div className="effectDirection"> + <div style={{ gridColumn: 1, gridRow: 2, justifySelf: 'center', color: targetDoc.presEffectDirection === "left" ? "#5a9edd" : "black" }} onClick={() => targetDoc.presEffectDirection = 'left'}><FontAwesomeIcon icon={"angle-right"} /></div> + <div style={{ gridColumn: 3, gridRow: 2, justifySelf: 'center', color: targetDoc.presEffectDirection === "right" ? "#5a9edd" : "black" }} onClick={() => targetDoc.presEffectDirection = 'right'}><FontAwesomeIcon icon={"angle-left"} /></div> + <div style={{ gridColumn: 2, gridRow: 1, justifySelf: 'center', color: targetDoc.presEffectDirection === "top" ? "#5a9edd" : "black" }} onClick={() => targetDoc.presEffectDirection = 'top'}><FontAwesomeIcon icon={"angle-down"} /></div> + <div style={{ gridColumn: 2, gridRow: 3, justifySelf: 'center', color: targetDoc.presEffectDirection === "bottom" ? "#5a9edd" : "black" }} onClick={() => targetDoc.presEffectDirection = 'bottom'}><FontAwesomeIcon icon={"angle-up"} /></div> + <div style={{ gridColumn: 2, gridRow: 2, width: 10, height: 10, alignSelf: 'center', justifySelf: 'center', border: targetDoc.presEffectDirection ? "solid 2px black" : "solid 2px #5a9edd", borderRadius: "100%" }} onClick={() => targetDoc.presEffectDirection = false}></div> + </div> + </div> + <div className="ribbon-final-box"> + {this._selectedArray.length} selected + <div className="selectedList"> + {this.listOfSelected} + </div> + </div> + <div className="ribbon-final-box"> + <div className={this._selectedArray.length === 0 ? "ribbon-final-button" : "ribbon-final-button-hidden"} onClick={() => this.applyTo(this._selectedArray)}> + Apply to selected + </div> + <div className="ribbon-final-button-hidden" onClick={() => this.applyTo(this.childDocs)}> + Apply to all + </div> + </div> + </div> + ); + } + } + + applyTo = (array: Doc[]) => { + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); + array.forEach((doc, index) => { + const curDoc = Cast(doc, Doc, null); + const tagDoc = Cast(curDoc.presentationTargetDoc, Doc, null); + if (tagDoc && targetDoc) { + tagDoc.presTransition = targetDoc.presTransition; + tagDoc.presDuration = targetDoc.presDuration; + tagDoc.presEffect = targetDoc.presEffect; + } + }); + } + + public inputRef = React.createRef<HTMLInputElement>(); + + + createNewSlide = (title: string, type: string) => { + let doc = null; + if (type === "text") { + doc = Docs.Create.TextDocument("", { _nativeWidth: 400, _width: 400, title: title }); + const data = Cast(this.rootDoc.data, listSpec(Doc)); + if (data) data.push(doc); + } else { + doc = Docs.Create.FreeformDocument([], { _nativeWidth: 400, _width: 400, title: title }); + const data = Cast(this.rootDoc.data, listSpec(Doc)); + if (data) data.push(doc); + } + } + + @computed get newDocumentDropdown() { + let type = ""; + let title = ""; + return ( + <div> + <div className={`presBox-ribbon ${this.newDocumentTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> + <div className="ribbon-box"> + Slide Title: <br></br> + {/* <div className="dropdown-textInput"> */} + <input className="ribbon-textInput" placeholder="..." type="text" name="fname" ref={this.inputRef} onChange={(e) => { + e.stopPropagation(); + title = e.target.value; + }}></input> + {/* </div> */} + </div> + <div className="ribbon-box"> + Choose type: + <div style={{ display: "flex", alignSelf: "center" }}> + <div title="Text" className={`ribbon-button ${type === "text" ? "active" : ""}`} onClick={() => { type = "text"; }}>Text</div> + <div title="Freeform" className={`ribbon-button ${type === "freeform" ? "active" : ""}`} onClick={() => { type = "freeform"; }}>Freeform</div> + </div> + </div> + <div className="ribbon-final-box"> + <div className="ribbon-final-button" onClick={() => this.createNewSlide(title, type)}> + Create New Slide + </div> + </div> + </div> + </div > + ); + } + + @computed get playDropdown() { + return ( + <div className={`dropdown-play ${this.playTools ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> + <div className="dropdown-play-button" onClick={() => this.startOrResetPres(this.itemIndex)}> + Start from current slide + </div> + <div className="dropdown-play-button" onClick={() => this.startOrResetPres(0)}> + Start from first slide + </div> + </div> + ); + } + + progressivizeOptions = (viewType: string) => { + const buttons = []; + buttons.push(<div className="ribbon-button" title="Progressivize child documents" onClick={this.progressivize}>Progressivize child documents</div>); + buttons.push(<div className="ribbon-button" title="Internal navigation" onClick={() => console.log("hide after")}>Internal navigation</div>); + if (viewType === "rtf") { + buttons.push(<div className="ribbon-button" title="Progressivize bullet points" onClick={() => console.log("hide after")}>Bullet points</div>); + } + return buttons; + } + + + + @computed get progressivizeDropdown() { + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); + + if (activeItem && targetDoc) { + return ( + <div> + <div className={`presBox-ribbon ${this.progressivizeTools && this.layoutDoc.presStatus === "edit" ? "active" : ""}`} onClick={e => e.stopPropagation()} onPointerUp={e => e.stopPropagation()} onPointerDown={e => e.stopPropagation()}> + <div className="ribbon-box"> + {targetDoc.type} selected + <div className="selectedList"> + <div className="selectedList-items">1. {targetDoc.title}</div> + </div> + </div> + <div className="ribbon-final-box"> + <div className="progressivizeEdit"> + <div className="ribbon-button" style={{ backgroundColor: activeItem.presProgressivize ? "#aedef8" : "" }} title="Progressivize child documents" onClick={this.progressivize}>Progressivize child documents</div> + <div className="ribbon-button" style={{ display: activeItem.presProgressivize ? "block" : "none", backgroundColor: targetDoc.editProgressivize ? "#aedef8" : "" }} title="Edit progresivize" onClick={this.editProgressivize}>Edit</div> + </div> + <div className="ribbon-button" title="Internal navigation" onClick={() => console.log("hide after")}>Internal navigation</div> + </div> + </div> + </div> + ); + } + } + + @action + editProgressivize = (e: React.MouseEvent) => { + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); + targetDoc.currentFrame = targetDoc.lastFrame; + if (targetDoc?.editProgressivize) { + targetDoc.editProgressivize = false; + } else { + targetDoc.editProgressivize = true; + } + } + + @action + progressivize = (e: React.MouseEvent) => { + e.stopPropagation(); + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + activeItem.presProgressivize = !activeItem.presProgressivize; + const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); + const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]); + targetDoc.presProgressivize = !targetDoc.presProgressivize; + console.log(targetDoc.presProgressivize); + if (activeItem.presProgressivize) { + console.log("progressivize"); + targetDoc.currentFrame = 0; + CollectionFreeFormDocumentView.setupKeyframes(docs, docs.length, true); + targetDoc.lastFrame = docs.length - 1; + } + } + + @computed get progressivizeChildDocs() { + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const targetDoc = Cast(activeItem?.presentationTargetDoc, Doc, null); + const docs = DocListCast(targetDoc[Doc.LayoutFieldKey(targetDoc)]); + const tags: JSX.Element[] = []; + docs.forEach((doc, index) => { + tags.push( + <div className="progressivizeButton" style={{ top: NumCast(doc.y), left: NumCast(doc.x) }}>{doc.appearFrame}</div> + ); + }); + return tags; + } + + + + @computed get moreInfoDropdown() { + return (<div></div>); + } + + @computed get effectOpenBracket() { + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); + if (targetDoc.presEffect && this.itemIndex) { + return ("<" + targetDoc.presEffect + "when=" + this.layoutDoc === PresBox.Instance.childDocs[this.itemIndex].presentationTargetDoc + ">"); + } else return; + } + + @computed get effectCloseBracket() { + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + const targetDoc = Cast(activeItem.presentationTargetDoc, Doc, null); + if (targetDoc.presEffect && this.itemIndex) { + return ("</" + targetDoc.presEffect + ">"); + } else return; + } + + @computed get toolbar() { + const activeItem = Cast(this.childDocs[this.itemIndex], Doc, null); + + if (activeItem) { + return ( + <> + <div className={`toolbar-button ${this.newDocumentTools ? "active" : ""}`} onClick={this.toggleNewDocument}><FontAwesomeIcon icon={"plus"} /> + <FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} /> + </div> + <div className="toolbar-divider" /> + <div className={`toolbar-button ${this.pathBoolean ? "active" : ""}`}><FontAwesomeIcon title={"View Paths"} icon={"object-group"} onClick={this.viewPaths} /></div> + {/* <div className="toolbar-button"><FontAwesomeIcon title={"Portal"} icon={"eye"} onClick={this.toolbarTest} /></div> */} + <div className="toolbar-divider" /> + <div className={`toolbar-button ${this.transitionTools ? "active" : ""}`} onClick={this.toggleTransitionTools}> + <FontAwesomeIcon icon={"rocket"} /> + <div className="toolbar-buttonText"> Transitions</div> + <FontAwesomeIcon className={`dropdown ${this.transitionTools ? "active" : ""}`} icon={"angle-down"} /> + </div> + <div className="toolbar-divider" /> + <div className={`toolbar-button ${this.progressivizeTools ? "active" : ""}`} onClick={this.toggleProgressivize}> + <FontAwesomeIcon icon={"tasks"} /> + <div className="toolbar-buttonText"> Progressivize</div> + <FontAwesomeIcon className={`dropdown ${this.progressivizeTools ? "active" : ""}`} icon={"angle-down"} /> + </div> + <div className="toolbar-divider" /> + <div className="toolbar-button"> + <FontAwesomeIcon className={"toolbar-thumbtack"} icon={"thumbtack"} /> + </div> + <div className={`toolbar-button ${this.moreInfoTools ? "active" : ""}`} onClick={this.toggleMoreInfo}> + <div className={`toolbar-moreInfo ${this.moreInfoTools ? "active" : ""}`}> + <div className="toolbar-moreInfoBall" /> + <div className="toolbar-moreInfoBall" /> + <div className="toolbar-moreInfoBall" /> + </div> + </div> + </> + ); + } else { + return ( + <> + <div className="toolbar-button"><FontAwesomeIcon icon={"plus"} onClick={this.toggleNewDocument} /> + <FontAwesomeIcon className={`dropdown ${this.newDocumentTools ? "active" : ""}`} icon={"angle-down"} /> + </div> + <div className="toolbar-button"> + <FontAwesomeIcon className={"toolbar-thumbtack"} icon={"thumbtack"} /> + </div> + <Fade left when={this.moreInfoTools}> + <h1>uppercase</h1> + </Fade> + <div className={`toolbar-button ${this.moreInfoTools ? "active" : ""}`} onClick={this.toggleMoreInfo}> + <div className={`toolbar-moreInfo ${this.moreInfoTools ? "active" : ""}`}> + <div className="toolbar-moreInfoBall" /> + <div className="toolbar-moreInfoBall" /> + <div className="toolbar-moreInfoBall" /> + </div> + </div> + </> + ); + } + } + + render() { this.childDocs.slice(); // needed to insure that the childDocs are loaded for looking up fields const mode = StrCast(this.rootDoc._viewType) as CollectionViewType; return <div className="presBox-cont" style={{ minWidth: this.layoutDoc.inOverlay ? 240 : undefined }} > @@ -315,16 +988,33 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Time}>Time</option> <option onPointerDown={e => e.stopPropagation()} value={CollectionViewType.Carousel}>Slides</option> </select> - <div className="presBox-button" title="Back" style={{ gridColumn: 2 }} onClick={this.back}> - <FontAwesomeIcon icon={"arrow-left"} /> - </div> - <div className="presBox-button" title={"Reset Presentation" + this.layoutDoc.presStatus ? "" : " From Start"} style={{ gridColumn: 3 }} onClick={this.startOrResetPres}> - <FontAwesomeIcon icon={this.layoutDoc.presStatus ? "stop" : "play"} /> - </div> - <div className="presBox-button" title="Next" style={{ gridColumn: 4 }} onClick={this.next}> - <FontAwesomeIcon icon={"arrow-right"} /> + <div className="presBox-presentPanel"> + <div className={`presBox-button ${this.layoutDoc.presStatus !== "edit" ? "active" : ""}`} title={"Reset Presentation" + this.layoutDoc.presStatus ? "" : " From Start"} style={{ gridColumn: 2 }} onClick={() => this.startOrResetPres(0)}> + <FontAwesomeIcon icon={"clock"} /> + <FontAwesomeIcon icon={this.layoutDoc.presStatus === "auto" ? "pause" : "play"} /> + <div className="toolbar-divider" style={{ marginLeft: 5 }} /> + <FontAwesomeIcon onClick={e => { e.stopPropagation; this.togglePlay(); }} className="dropdown" icon={"angle-down"} /> + {this.playDropdown} + </div> + <div className={`presBox-button ${this.layoutDoc.presStatus === "edit" ? "present" : ""}`} title="Present" onClick={() => this.layoutDoc.presStatus = "manual"}> + <FontAwesomeIcon className="present-icon" icon={"play-circle"} /> Present + </div> + <div className={`presBox-button ${this.layoutDoc.presStatus !== "edit" ? "active" : ""}`} title="Back" onClick={this.back}> + <FontAwesomeIcon icon={"arrow-left"} /> + </div> + <div className={`presBox-button ${this.layoutDoc.presStatus !== "edit" ? "active" : ""}`} title="Next" onClick={this.next}> + <FontAwesomeIcon icon={"arrow-right"} /> + </div> + <div className={`presBox-button ${this.layoutDoc.presStatus !== "edit" ? "edit" : ""}`} title="Next" onClick={() => this.layoutDoc.presStatus = "edit"}> + <FontAwesomeIcon icon={"times"} /> + </div> </div> </div> + <div className={`presBox-toolbar ${this.layoutDoc.presStatus === "edit" ? "active" : ""}`}> {this.toolbar} </div> + {this.newDocumentDropdown} + {this.moreInfoDropdown} + {this.transitionDropdown} + {this.progressivizeDropdown} <div className="presBox-listCont" > {mode !== CollectionViewType.Invalid ? <CollectionView {...this.props} @@ -334,10 +1024,11 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps, PresBoxSchema> moveDocument={returnFalse} childOpacity={returnOne} childLayoutTemplate={this.childLayoutTemplate} - filterAddDocument={this.addDocumentFilter} + filterAddDocument={returnFalse} removeDocument={returnFalse} dontRegisterView={true} focus={this.selectElement} + presMultiSelect={this.multiSelect} ScreenToLocalTransform={this.getTransform} /> : (null) } @@ -353,3 +1044,11 @@ Scripting.addGlobal(function lookupPresBoxField(container: Doc, field: string, d if (field === 'presBox') return container; return undefined; }); + + + + // console.log("render = " + this.layoutDoc.title + " " + this.layoutDoc.presStatus); + // const presOrderedDocs = DocListCast(activeItem.presOrderedDocs); + // if (presOrderedDocs.length != this.childDocs.length || presOrderedDocs.some((pd, i) => pd !== this.childDocs[i])) { + // this.rootDoc.presOrderedDocs = new List<Doc>(this.childDocs.slice()); + // }
\ No newline at end of file |
