diff options
Diffstat (limited to 'src')
9 files changed, 47 insertions, 30 deletions
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts index f7d072d80..20c57c617 100644 --- a/src/client/util/CurrentUserUtils.ts +++ b/src/client/util/CurrentUserUtils.ts @@ -633,7 +633,7 @@ export class CurrentUserUtils { { title: "Left", toolTip: "Left align", btnType: ButtonType.ToggleButton, icon: "align-left", scripts: {onClick:'{ return setAlignment("left", _readOnly_);}' }}, { title: "Center", toolTip: "Center align", btnType: ButtonType.ToggleButton, icon: "align-center", scripts: {onClick:'{ return setAlignment("center", _readOnly_);}'} }, { title: "Right", toolTip: "Right align", btnType: ButtonType.ToggleButton, icon: "align-right", scripts: {onClick:'{ return setAlignment("right", _readOnly_);}'} }, - { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", scripts: {onClick:'{ return toggleNoAutoLinkAnchor(_readOnly_);}'}}, + { title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", scripts: {onClick:'{ return toggleNoAutoLinkAnchor(_readOnly_);}'}, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform") || IsNoviceMode()'}}, { title: "Dictate",toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", scripts: {onClick:'{ return toggleDictation(_readOnly_);}'}}, ]; } @@ -676,7 +676,7 @@ export class CurrentUserUtils { CollectionViewType.Grid, CollectionViewType.NoteTaking]), title: "Perspective", toolTip: "View", btnType: ButtonType.DropdownList, ignoreClick: true, width: 100, scripts: { script: 'setView(value, _readOnly_)'}}, { title: "Back", icon: "chevron-left", toolTip: "Prev Animation Frame", btnType: ButtonType.ClickButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform") || IsNoviceMode()'}, width: 20, scripts: { onClick: 'prevKeyFrame(_readOnly_)'}}, - { title: "Num", icon: "", toolTip: "Frame Number", btnType: ButtonType.TextButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform") || IsNoviceMode()', buttonText: 'selectedDocs()?.lastElement().currentFrame.toString()'}, width: 20, scripts: {}}, + { title: "Num", icon: "", toolTip: "Frame Number", btnType: ButtonType.TextButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform") || IsNoviceMode()', buttonText: 'selectedDocs()?.lastElement().currentFrame.toString()'}, width: 20, scripts: {}}, { title: "Fwd", icon: "chevron-right", toolTip: "Next Animation Frame", btnType: ButtonType.ClickButton, funcs: {hidden: '!SelectionManager_selectedDocType(undefined, "freeform") || IsNoviceMode()'}, width: 20, scripts: { onClick: 'nextKeyFrame(_readOnly_)'}}, { title: "Fill", icon: "fill-drip", toolTip: "Background Fill Color",btnType: ButtonType.ColorButton, funcs: {hidden: '!SelectionManager_selectedDocType()'}, ignoreClick: true, width: 20, scripts: { script: 'return setBackgroundColor(value, _readOnly_)'}}, // Only when a document is selected { title: "Header", icon: "heading", toolTip: "Header Color", btnType: ButtonType.ColorButton, funcs: {hidden: '!SelectionManager_selectedDocType()'}, ignoreClick: true, scripts: { script: 'return setHeaderColor(value, _readOnly_)'}}, diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx index 6d1397395..ab77af0f4 100644 --- a/src/client/views/DocumentDecorations.tsx +++ b/src/client/views/DocumentDecorations.tsx @@ -203,8 +203,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P if (this._deleteAfterIconify) { views.forEach(iconView => { Doc.setNativeView(iconView.props.Document); - if (iconView.props.Document.isInkMask && iconView.props.Document.activeFrame !== undefined) { - iconView.props.Document.opacity = 0; // bcz: hacky ... allows inkMaks to be "turned off" without removing them from the collection which allows them to function properly in a presenation. + if (iconView.props.Document.activeFrame) { + iconView.props.Document.opacity = 0; // bcz: hacky ... allows inkMasks and other documents to be "turned off" without removing them from the animated collection which allows them to function properly in a presenation. } else { iconView.props.removeDocument?.(iconView.props.Document); } diff --git a/src/client/views/InkStrokeProperties.ts b/src/client/views/InkStrokeProperties.ts index b32c9d54c..1f5f16592 100644 --- a/src/client/views/InkStrokeProperties.ts +++ b/src/client/views/InkStrokeProperties.ts @@ -68,7 +68,6 @@ export class InkStrokeProperties { doc.x = oldXrange.coord + (newXrange.min - oldXrange.min) * ptsXscale; doc.y = oldYrange.coord + (newYrange.min - oldYrange.min) * ptsYscale; if (doc.activeFrame !== undefined) { - doc.data = ComputedField.MakeInterpolated('data', 'activeFrame', doc, NumCast(doc.activeFrame)); const findexed = Cast(doc[`data-indexed`], listSpec(InkField), []).slice(); findexed[NumCast(doc.activeFrame)] = new InkField(newPoints); doc[`data-indexed`] = new List<InkField>(findexed); diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx index 52efbdfd7..520d40abf 100644 --- a/src/client/views/InkingStroke.tsx +++ b/src/client/views/InkingStroke.tsx @@ -25,7 +25,7 @@ import { action, IReactionDisposer, observable, reaction } from 'mobx'; import { observer } from 'mobx-react'; import { Doc, HeightSym, WidthSym } from '../../fields/Doc'; import { InkData, InkField, InkTool } from '../../fields/InkField'; -import { BoolCast, Cast, NumCast, RTFCast, StrCast } from '../../fields/Types'; +import { BoolCast, Cast, FieldValue, NumCast, RTFCast, StrCast } from '../../fields/Types'; import { TraceMobx } from '../../fields/util'; import { OmitKeys, returnFalse, setupMoveUpEvents } from '../../Utils'; import { CognitiveServices } from '../cognitive_services/CognitiveServices'; @@ -45,6 +45,9 @@ import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox'; import { INK_MASK_SIZE } from './global/globalCssVariables.scss'; import './InkStroke.scss'; import Color = require('color'); +import { ComputedField } from '../../fields/ScriptField'; +import { listSpec } from '../../fields/Schema'; +import { List } from '../../fields/List'; @observer export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { @@ -56,7 +59,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { return inkData && inkData.lastElement().X === inkData[0].X && inkData.lastElement().Y === inkData[0].Y; } private _handledClick = false; // flag denoting whether ink stroke has handled a psuedo-click onPointerUp so that the real onClick event can be stopPropagated - private _selDisposer?: IReactionDisposer; + private _disposers: { [key: string]: IReactionDisposer } = {}; @observable _nearestSeg?: number; // nearest Bezier segment along the ink stroke to the cursor (used for displaying the Add Point highlight) @observable _nearestT?: number; // nearest t value within the nearest Bezier segment " @@ -64,13 +67,24 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() { componentDidMount() { this.props.setContentView?.(this); - this._selDisposer = reaction( + this._disposers.activeFrame = reaction( + () => this.rootDoc.activeFrame !== undefined && !(ComputedField.WithoutComputed(() => FieldValue(this.rootDoc[this.fieldKey])) instanceof ComputedField), + () => { + const newPoints = Cast(this.rootDoc[this.fieldKey], InkField, null).inkData; + this.rootDoc[this.fieldKey] = ComputedField.MakeInterpolated(this.fieldKey, 'activeFrame', this.rootDoc, NumCast(this.rootDoc.activeFrame)); + const findexed = Cast(this.rootDoc[`data-indexed`], listSpec(InkField), []).slice(); + findexed[NumCast(this.rootDoc.activeFrame)] = new InkField(newPoints); + this.rootDoc[this.fieldKey + '-indexed'] = new List<InkField>(findexed); + }, + { fireImmediately: true } + ); + this._disposers.selfDisper = reaction( () => this.props.isSelected(), // react to stroke being deselected by turning off ink handles selected => !selected && (InkStrokeProperties.Instance._controlButton = false) ); } componentWillUnmount() { - this._selDisposer?.(); + Object.keys(this._disposers).forEach(key => this._disposers[key]()); } // transform is the inherited screentolocal xf plus any scaling that was done to make the stroke diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx index ee01c341b..b210e7d9a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx @@ -45,7 +45,7 @@ export interface PoolData { export interface ViewDefResult { ele: JSX.Element; bounds?: ViewDefBounds; - inkMask?: boolean; + inkMask?: number; //sort elements into either the mask layer (which has a mixedBlendMode appropriate for transparent masks), or the regular documents layer; -1 = no mask, 0 = mask layer but stroke is transprent (hidden), >0 = mask layer and not hidden } function toLabel(target: FieldResult<Field>) { if (typeof target === 'number' || Number(target)) { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss index 010132aa5..d80fcdfc3 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss @@ -20,15 +20,20 @@ pointer-events: none; } +.collectionfreeformview-mask-empty, .collectionfreeformview-mask { - mix-blend-mode: multiply; z-index: 5000; width: $INK_MASK_SIZE; height: $INK_MASK_SIZE; transform: translate($INK_MASK_SIZE_HALF, $INK_MASK_SIZE_HALF); - background-color: rgba(0, 0, 0, 0.7); pointer-events: none; position: absolute; + background-color: transparent; + transition: background-color 1s ease 0s; +} +.collectionfreeformview-mask { + mix-blend-mode: multiply; + background-color: rgba(0, 0, 0, 0.7); } .collectionfreeformview-viewdef { diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx index 0fd326091..1d518076a 100644 --- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx +++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx @@ -119,9 +119,9 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection @observable ChildDrag: DocumentView | undefined; // child document view being dragged. needed to update drop areas of groups when a group item is dragged. @computed get views() { - const viewsMask = this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z && ele.inkMask).map(ele => ele.ele); - const renderableEles = this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z && !ele.inkMask).map(ele => ele.ele); - if (viewsMask.length) renderableEles.push(<div className="collectionfreeformview-mask">{viewsMask}</div>); + const viewsMask = this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z && ele.inkMask !== -1).map(ele => ele.ele); + const renderableEles = this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z && ele.inkMask === -1).map(ele => ele.ele); + if (viewsMask.length) renderableEles.push(<div className={`collectionfreeformview-mask${this._layoutElements.some(ele => (ele.inkMask ?? 0) > 0) ? '' : '-empty'}`}>{viewsMask}</div>); return renderableEles; } @computed get fitToContentVals() { @@ -251,7 +251,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection }; isCurrent(doc: Doc) { - if (doc.isInkMask && doc.opacity === 0) return false; // bcz: hacky --- allows inkMasks to be "turned off" in a presentation without removing them from the collection. otherwise, they still render a gray background.. need to come back to this and fix. const dispTime = NumCast(doc._timecodeToShow, -1); const endTime = NumCast(doc._timecodeToHide, dispTime + 1.5); const curTime = NumCast(this.Document._currentTimecode, -1); @@ -1465,7 +1464,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection elements.push({ ele: this.getChildDocView(entry[1]), bounds: this.childDataProvider(entry[1].pair.layout, entry[1].replica), - inkMask: BoolCast(entry[1].pair.layout.isInkMask), + inkMask: BoolCast(entry[1].pair.layout.isInkMask) ? NumCast(entry[1].pair.layout.opacity) : -1, }) ); diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx index 172adcafe..74143a731 100644 --- a/src/client/views/nodes/DocumentView.tsx +++ b/src/client/views/nodes/DocumentView.tsx @@ -1656,7 +1656,6 @@ export class DocumentView extends React.Component<DocumentViewProps> { ref={this.ContentRef} style={{ transition: this.props.dataTransition, - //position: this.props.Document.isInkMask ? 'absolute' : undefined, transform: isButton ? undefined : `translate(${this.centeringX}px, ${this.centeringY}px)`, width: isButton || isPresTreeElement ? '100%' : xshift() ?? `${(100 * (this.props.PanelWidth() - this.Xshift * 2)) / this.props.PanelWidth()}%`, height: diff --git a/src/client/views/nodes/button/FontIconBox.tsx b/src/client/views/nodes/button/FontIconBox.tsx index cb68c1ac3..fc5bf86f4 100644 --- a/src/client/views/nodes/button/FontIconBox.tsx +++ b/src/client/views/nodes/button/FontIconBox.tsx @@ -90,9 +90,11 @@ export class FontIconBox extends DocComponent<ButtonProps>() { @computed get label() { return StrCast(this.rootDoc.label, StrCast(this.rootDoc.title)); } - @computed get icon() { - return StrCast(this.dataDoc.icon, 'user') as any; - } + Icon = (color: string) => { + const icon = StrCast(this.dataDoc.icon, 'user') as any; + const trailsIcon = () => <img src={`/assets/${'presTrails.png'}`} style={{ width: 30, height: 30, filter: `invert(${color === Colors.DARK_GRAY ? '0%' : '100%'})` }} />; + return !icon ? null : icon === 'pres-trail' ? trailsIcon() : <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={icon} color={color} />; + }; @computed get dropdown() { return BoolCast(this.rootDoc.dropDownOpen); } @@ -228,7 +230,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() { className={`menuButton ${this.type} ${active}`} style={{ color: color, backgroundColor: backgroundColor, borderBottomLeftRadius: this.dropdown ? 0 : undefined }} onClick={action(() => (this.rootDoc.dropDownOpen = !this.rootDoc.dropDownOpen))}> - <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} /> + {this.Icon(color)} {!this.label || !FontIconBox.GetShowLabels() ? null : ( <div className="fontIconBox-label" style={{ color: color, backgroundColor: backgroundColor }}> {' '} @@ -384,7 +386,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() { style={{ color: color, borderBottomLeftRadius: this.dropdown ? 0 : undefined }} onClick={action(() => (this.colorPickerClosed = !this.colorPickerClosed))} onPointerDown={e => e.stopPropagation()}> - <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} /> + {this.Icon(color)} <div className="colorButton-color" style={{ backgroundColor: curColor }} /> {label} {/* {dropdownCaret} */} @@ -436,7 +438,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() { } else { return ( <div className={`menuButton ${this.type + (FontIconBox.GetShowLabels() ? 'Label' : '')}`} style={{ opacity: 1, backgroundColor, color }}> - <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} /> + {this.Icon(color)} {label} </div> ); @@ -453,7 +455,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() { return ( <div className={`menuButton ${this.type}`} onContextMenu={this.specificContextMenu} style={{ backgroundColor: 'transparent', borderBottomLeftRadius: this.dropdown ? 0 : undefined }}> <div className="menuButton-wrap"> - <FontAwesomeIcon className={`menuButton-icon-${this.type}`} icon={this.icon} color={'black'} size={'sm'} /> + {this.Icon(color)} {!this.label || !FontIconBox.GetShowLabels() ? null : ( <div className="fontIconBox-label" style={{ color: color, backgroundColor: backgroundColor }}> {' '} @@ -506,7 +508,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() { case ButtonType.TextButton: button = ( <div className={`menuButton ${this.type}`} style={{ color, backgroundColor, opacity: 1, gridAutoColumns: `${NumCast(this.rootDoc._height)} auto` }}> - <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} /> + {this.Icon(color)} {StrCast(this.rootDoc.buttonText) ? <div className="button-text">{StrCast(this.rootDoc.buttonText)}</div> : null} {label} </div> @@ -531,7 +533,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() { case ButtonType.ToolButton: button = ( <div className={`menuButton ${this.type + (FontIconBox.GetShowLabels() ? 'Label' : '')}`} style={{ opacity: 1, backgroundColor, color }}> - <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} /> + {this.Icon(color)} {label} </div> ); @@ -543,16 +545,15 @@ export class FontIconBox extends DocComponent<ButtonProps>() { case ButtonType.ClickButton: button = ( <div className={`menuButton ${this.type + (FontIconBox.GetShowLabels() ? 'Label' : '')}`} style={{ color, backgroundColor, opacity: 1 }}> - <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} /> + {this.Icon(color)} {label} </div> ); break; case ButtonType.MenuButton: - const trailsIcon = <img src={`/assets/${'presTrails.png'}`} style={{ width: 30, height: 30, filter: `invert(${color === Colors.DARK_GRAY ? '0%' : '100%'})` }} />; button = ( <div className={`menuButton ${this.type}`} style={{ color, backgroundColor }}> - {this.icon === 'pres-trail' ? trailsIcon : <FontAwesomeIcon className={`fontIconBox-icon-${this.type}`} icon={this.icon} color={color} />} + {this.Icon(color)} {menuLabel} <FontIconBadge value={Cast(this.Document.badgeValue, 'string', null)} /> </div> |