aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2022-08-11 19:01:37 -0400
committerbobzel <zzzman@gmail.com>2022-08-11 19:01:37 -0400
commit081632757af3c2ec2e4482c1e5fe710c8ee6cad8 (patch)
tree4897685a59f6ef2f38ebe511908ab9d46eac01bf /src
parent513dcaa2d8c86f1cb5236ce89062cace6f418d1b (diff)
added better ui and backend support for mask ink strokes. added frame #'s ui for seeing current animation frame.
Diffstat (limited to 'src')
-rw-r--r--src/client/documents/Documents.ts19
-rw-r--r--src/client/util/CurrentUserUtils.ts6
-rw-r--r--src/client/util/DragManager.ts14
-rw-r--r--src/client/views/InkingStroke.tsx28
-rw-r--r--src/client/views/MainView.tsx1
-rw-r--r--src/client/views/collections/CollectionMenu.tsx2
-rw-r--r--src/client/views/collections/TabDocView.tsx10
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx1
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss23
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx9
-rw-r--r--src/client/views/global/globalCssVariables.scss13
-rw-r--r--src/client/views/global/globalCssVariables.scss.d.ts6
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx7
-rw-r--r--src/client/views/nodes/DocumentView.tsx6
-rw-r--r--src/client/views/nodes/button/FontIconBox.tsx34
-rw-r--r--src/client/views/nodes/trails/PresBox.tsx36
-rw-r--r--src/fields/InkField.ts40
17 files changed, 162 insertions, 93 deletions
diff --git a/src/client/documents/Documents.ts b/src/client/documents/Documents.ts
index c7ea04839..cf9ed43e1 100644
--- a/src/client/documents/Documents.ts
+++ b/src/client/documents/Documents.ts
@@ -31,7 +31,7 @@ import { CollectionView } from '../views/collections/CollectionView';
import { ContextMenu } from '../views/ContextMenu';
import { ContextMenuProps } from '../views/ContextMenuItem';
import { DFLT_IMAGE_NATIVE_DIM } from '../views/global/globalCssVariables.scss';
-import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, InkingStroke } from '../views/InkingStroke';
+import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke } from '../views/InkingStroke';
import { AudioBox } from '../views/nodes/AudioBox';
import { FontIconBox } from '../views/nodes/button/FontIconBox';
import { ColorBox } from '../views/nodes/ColorBox';
@@ -918,9 +918,22 @@ export namespace Docs {
return linkDoc;
}
- export function InkDocument(color: string, tool: string, strokeWidth: number, strokeBezier: string, fillColor: string, arrowStart: string, arrowEnd: string, dash: string, points: PointData[], options: DocumentOptions = {}) {
+ export function InkDocument(
+ color: string,
+ tool: string,
+ strokeWidth: number,
+ strokeBezier: string,
+ fillColor: string,
+ arrowStart: string,
+ arrowEnd: string,
+ dash: string,
+ points: PointData[],
+ isInkMask: boolean,
+ options: DocumentOptions = {}
+ ) {
const I = new Doc();
I[Initializing] = true;
+ I.isInkMask = isInkMask;
I.type = DocumentType.INK;
I.layout = InkingStroke.LayoutString('data');
I.color = color;
@@ -1424,7 +1437,7 @@ export namespace DocUtils {
created = Docs.Create.RecordingDocument(field.url.href, resolved);
layout = RecordingBox.LayoutString;
} else if (field instanceof InkField) {
- created = Docs.Create.InkDocument(ActiveInkColor(), Doc.ActiveTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), field.inkData, resolved);
+ created = Docs.Create.InkDocument(ActiveInkColor(), Doc.ActiveTool, ActiveInkWidth(), ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), field.inkData, ActiveIsInkMask(), resolved);
layout = InkingStroke.LayoutString;
} else if (field instanceof List && field[0] instanceof Doc) {
created = Docs.Create.StackingDocument(DocListCast(field), resolved);
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index d19874720..dcf4a71c8 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -645,8 +645,9 @@ export class CurrentUserUtils {
// { title: "Highlighter", toolTip: "Highlighter (Ctrl+H)", btnType: ButtonType.ToggleButton, icon: "highlighter", scripts:{onClick: 'setActiveTool("highlighter")'} },
{ title: "Circle", toolTip: "Circle (Ctrl+Shift+C)", btnType: ButtonType.ToggleButton, icon: "circle", scripts: {onClick:'{ return setActiveTool("circle", _readOnly_);}'} },
// { title: "Square", toolTip: "Square (Ctrl+Shift+S)", btnType: ButtonType.ToggleButton, icon: "square", click: 'setActiveTool("square")' },
- { title: "Line", toolTip: "Line (Ctrl+Shift+L)", btnType: ButtonType.ToggleButton, icon: "minus", scripts: {onClick: '{ return setActiveTool("line", _readOnly_);}' }},
- { title: "Fill", toolTip: "Fill color", btnType: ButtonType.ColorButton, icon: "fill-drip",ignoreClick: true, scripts: {script: "{ return setFillColor(value, _readOnly_);}"} },
+ { title: "Line", toolTip: "Line (Ctrl+Shift+L)", btnType: ButtonType.ToggleButton, icon: "minus", scripts: {onClick:'{ return setActiveTool("line", _readOnly_);}' }},
+ { title: "Mask", toolTip: "Mask", btnType: ButtonType.ToggleButton, icon: "user-circle", scripts: {onClick:'{ return setIsInkMask(_readOnly_);}'} },
+ { title: "Fill", toolTip: "Fill color", btnType: ButtonType.ColorButton, icon: "fill-drip",ignoreClick: true, scripts: {script: '{ return setFillColor(value, _readOnly_);}'} },
{ title: "Width", toolTip: "Stroke width", btnType: ButtonType.NumberButton, ignoreClick: true, scripts: {script: '{ return setStrokeWidth(value, _readOnly_);}'}, numBtnType: NumButtonType.Slider, numBtnMin: 1},
{ title: "Color", toolTip: "Stroke color", btnType: ButtonType.ColorButton, icon: "pen", ignoreClick: true, scripts: {script: '{ return setStrokeColor(value, _readOnly_);}'} },
];
@@ -674,6 +675,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: "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/util/DragManager.ts b/src/client/util/DragManager.ts
index ccd94c56e..d781a87ab 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -377,14 +377,14 @@ export namespace DragManager {
}
const rect = ele.getBoundingClientRect();
const scaleX = rect.width / (ele.offsetWidth || rect.width);
- const scaleY = ele.offsetHeight ? rect.height / (ele.offsetHeight || rect.height) : scaleX;
+ const scaleY = scaleX; //ele.offsetHeight ? rect.height / (ele.offsetHeight || rect.height) : scaleX;
elesCont.left = Math.min(rect.left, elesCont.left);
elesCont.top = Math.min(rect.top, elesCont.top);
elesCont.right = Math.max(rect.right, elesCont.right);
elesCont.bottom = Math.max(rect.bottom, elesCont.bottom);
- xs.push(rect.left);
- ys.push(rect.top);
+ xs.push(rect.left + (options?.offsetX || 0));
+ ys.push(rect.top + (options?.offsetY || 0));
scaleXs.push(scaleX);
scaleYs.push(scaleY);
Object.assign(dragElement.style, {
@@ -401,9 +401,9 @@ export namespace DragManager {
transformOrigin: '0 0',
width: `${rect.width / scaleX}px`,
height: `${rect.height / scaleY}px`,
- transform: `translate(${rect.left + (options?.offsetX || 0)}px, ${rect.top + (options?.offsetY || 0)}px) scale(${scaleX}, ${scaleY})`,
+ transform: `translate(${xs[0]}px, ${ys[0]}px) scale(${scaleX}, ${scaleY})`,
});
- dragLabel.style.transform = `translate(${rect.left + (options?.offsetX || 0)}px, ${rect.top + (options?.offsetY || 0) - 20}px)`;
+ dragLabel.style.transform = `translate(${xs[0]}px, ${ys[0] - 20}px)`;
if (docsToDrag.length) {
const pdfBox = dragElement.getElementsByTagName('canvas');
@@ -543,8 +543,8 @@ export namespace DragManager {
const moveVec = { x: x - lastPt.x, y: y - lastPt.y };
lastPt = { x, y };
- dragLabel.style.transform = `translate(${xs[0] + moveVec.x + (options?.offsetX || 0)}px, ${ys[0] + moveVec.y + (options?.offsetY || 0) - 20}px)`;
- dragElements.map((dragElement, i) => (dragElement.style.transform = `translate(${(xs[i] += moveVec.x) + (options?.offsetX || 0)}px, ${(ys[i] += moveVec.y) + (options?.offsetY || 0)}px) scale(${scaleXs[i]}, ${scaleYs[i]})`));
+ dragElements.map((dragElement, i) => (dragElement.style.transform = `translate(${(xs[i] += moveVec.x)}px, ${(ys[i] += moveVec.y)}px) scale(${scaleXs[i]}, ${scaleYs[i]})`));
+ dragLabel.style.transform = `translate(${xs[0]}px, ${ys[0] - 20}px)`;
};
const upHandler = (e: PointerEvent) => {
clearTimeout(startWindowDragTimer);
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index e5de7a0c5..2671aea56 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -23,9 +23,9 @@
import React = require('react');
import { action, IReactionDisposer, observable, reaction } from 'mobx';
import { observer } from 'mobx-react';
-import { Doc, WidthSym } from '../../fields/Doc';
+import { Doc, HeightSym, WidthSym } from '../../fields/Doc';
import { InkData, InkField, InkTool } from '../../fields/InkField';
-import { Cast, NumCast, RTFCast, StrCast } from '../../fields/Types';
+import { BoolCast, Cast, NumCast, RTFCast, StrCast } from '../../fields/Types';
import { TraceMobx } from '../../fields/util';
import { OmitKeys, returnFalse, setupMoveUpEvents } from '../../Utils';
import { CognitiveServices } from '../cognitive_services/CognitiveServices';
@@ -42,12 +42,13 @@ import { InkTangentHandles } from './InkTangentHandles';
import { DocComponentView } from './nodes/DocumentView';
import { FieldView, FieldViewProps } from './nodes/FieldView';
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
+import { INK_MASK_SIZE } from './global/globalCssVariables.scss';
import './InkStroke.scss';
import Color = require('color');
@observer
export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
- static readonly MaskDim = 50000; // choose a really big number to make sure mask fits over container (which in theory can be arbitrarily big)
+ static readonly MaskDim = INK_MASK_SIZE; // choose a really big number to make sure mask fits over container (which in theory can be arbitrarily big)
public static LayoutString(fieldStr: string) {
return FieldView.LayoutString(InkingStroke, fieldStr);
}
@@ -353,9 +354,18 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
const endMarker = StrCast(this.layoutDoc.strokeEndMarker);
const markerScale = NumCast(this.layoutDoc.strokeMarkerScale, 1);
const closed = InkingStroke.IsClosed(inkData);
- const fillColor = StrCast(this.layoutDoc.fillColor, 'transparent');
+ const isInkMask = BoolCast(this.layoutDoc.isInkMask);
+ const fillColor = isInkMask ? '#aaaaaa' : StrCast(this.layoutDoc.fillColor, 'transparent');
const strokeColor = !closed && fillColor && fillColor !== 'transparent' ? fillColor : StrCast(this.layoutDoc.color);
+ // bcz: Hack!! Not really sure why, but having fractional values for width/height of mask ink strokes causes the dragging clone (see DragManager) to be offset from where it should be.
+ if (isInkMask && (this.layoutDoc[WidthSym]() !== Math.round(this.layoutDoc[WidthSym]()) || this.layoutDoc[HeightSym]() !== Math.round(this.layoutDoc[HeightSym]()))) {
+ setTimeout(() => {
+ this.layoutDoc._width = Math.round(NumCast(this.layoutDoc[WidthSym]()));
+ this.layoutDoc._height = Math.round(NumCast(this.layoutDoc[HeightSym]()));
+ });
+ }
+
// Visually renders the polygonal line made by the user.
const inkLine = InteractionUtils.CreatePolyline(
inkData,
@@ -430,7 +440,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
className="inkStroke"
style={{
transform: this.props.Document.isInkMask ? `translate(${InkingStroke.MaskDim / 2}px, ${InkingStroke.MaskDim / 2}px)` : undefined,
- mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? 'multiply' : 'unset',
+ // mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? 'multiply' : 'unset',
cursor: this.props.isSelected() ? 'default' : undefined,
}}
{...(!closed ? interactions : {})}>
@@ -467,7 +477,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps>() {
className="inkStroke"
style={{
transform: this.props.Document.isInkMask ? `translate(${InkingStroke.MaskDim / 2}px, ${InkingStroke.MaskDim / 2}px)` : undefined,
- mixBlendMode: this.layoutDoc.tool === InkTool.Highlighter ? 'multiply' : 'unset',
+ mixBlendMode: 'unset',
cursor: this.props.isSelected() ? 'default' : undefined,
position: 'absolute',
}}
@@ -489,6 +499,9 @@ export function SetActiveBezierApprox(bezier: string): void {
export function SetActiveInkColor(value: string) {
ActiveInkPen() && (ActiveInkPen().activeInkColor = value);
}
+export function SetActiveIsInkMask(value: boolean) {
+ ActiveInkPen() && (ActiveInkPen().activeIsInkMask = value);
+}
export function SetActiveFillColor(value: string) {
ActiveInkPen() && (ActiveInkPen().activeFillColor = value);
}
@@ -513,6 +526,9 @@ export function ActiveInkColor(): string {
export function ActiveFillColor(): string {
return StrCast(ActiveInkPen()?.activeFillColor, '');
}
+export function ActiveIsInkMask(): boolean {
+ return BoolCast(ActiveInkPen()?.activeIsInkMask, false);
+}
export function ActiveArrowStart(): string {
return StrCast(ActiveInkPen()?.activeArrowStart, '');
}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index e96f65548..c166594e5 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -457,6 +457,7 @@ export class MainView extends React.Component {
fa.faVolumeDown,
fa.faSquareRootAlt,
fa.faVolumeMute,
+ fa.faUserCircle,
]
);
this.initAuthenticationRouters();
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index 8432619de..eb55650e4 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -1025,7 +1025,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionView
<FontAwesomeIcon icon={'caret-left'} size={'lg'} />
</div>
</Tooltip>
- <Tooltip key="num" title={<div className="dash-tooltip">Toggle View All</div>} placement="bottom">
+ <Tooltip key="num" title={<div className="dash-tooltip">Frame number</div>} placement="bottom">
<div
className="numKeyframe"
style={{ color: this.props.docView.ComponentView?.getKeyFrameEditing?.() ? 'white' : 'black', backgroundColor: this.props.docView.ComponentView?.getKeyFrameEditing?.() ? '#5B9FDD' : '#AEDDF8' }}
diff --git a/src/client/views/collections/TabDocView.tsx b/src/client/views/collections/TabDocView.tsx
index f30faab79..ff4b1e2ce 100644
--- a/src/client/views/collections/TabDocView.tsx
+++ b/src/client/views/collections/TabDocView.tsx
@@ -292,11 +292,11 @@ export class TabDocView extends React.Component<TabDocViewProps> {
pinDoc.presActiveFrame = pinProps?.activeFrame;
pinDoc.title = doc.title + ' (move)';
pinDoc.presMovement = PresMovement.Pan;
- if (pinDoc.isInkMask) {
- pinDoc.presHideAfter = true;
- pinDoc.presHideBefore = true;
- pinDoc.presMovement = PresMovement.None;
- }
+ }
+ if (pinDoc.isInkMask) {
+ pinDoc.presHideAfter = true;
+ pinDoc.presHideBefore = true;
+ pinDoc.presMovement = PresMovement.None;
}
if (curPres.expandBoolean) pinDoc.presExpandInlineButton = true;
PresBox.Instance?._selectedArray.clear();
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
index 3d85d32a0..ee01c341b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormLayoutEngines.tsx
@@ -45,6 +45,7 @@ export interface PoolData {
export interface ViewDefResult {
ele: JSX.Element;
bounds?: ViewDefBounds;
+ inkMask?: boolean;
}
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 79e063f7f..010132aa5 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.scss
@@ -1,4 +1,4 @@
-@import "../../global/globalCssVariables";
+@import '../../global/globalCssVariables';
.collectionfreeformview-none {
position: inherit;
@@ -20,8 +20,19 @@
pointer-events: none;
}
+.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;
+}
+
.collectionfreeformview-viewdef {
- >.collectionFreeFormDocumentView-container {
+ > .collectionFreeFormDocumentView-container {
pointer-events: none;
.contentFittingDocumentDocumentView-previewDoc {
@@ -210,13 +221,13 @@
}
}
- .collectionfreeformview>.jsx-parser {
+ .collectionfreeformview > .jsx-parser {
position: inherit;
height: 100%;
width: 100%;
}
- >.jsx-parser {
+ > .jsx-parser {
z-index: 0;
}
@@ -268,6 +279,6 @@
.pullpane-indicator {
z-index: 99999;
- background-color: rgba($color: #000000, $alpha: .4);
+ background-color: rgba($color: #000000, $alpha: 0.4);
position: absolute;
-} \ No newline at end of file
+}
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 82b377dfa..f3074543b 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -34,7 +34,7 @@ import { COLLECTION_BORDER_WIDTH } from '../../../views/global/globalCssVariable
import { Timeline } from '../../animationtimeline/Timeline';
import { ContextMenu } from '../../ContextMenu';
import { GestureOverlay } from '../../GestureOverlay';
-import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke';
+import { ActiveArrowEnd, ActiveArrowStart, ActiveDash, ActiveFillColor, ActiveInkBezierApprox, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, InkingStroke, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke';
import { LightboxView } from '../../LightboxView';
import { CollectionFreeFormDocumentView } from '../../nodes/CollectionFreeFormDocumentView';
import { DocFocusOptions, DocumentView, DocumentViewProps, ViewAdjustment, ViewSpecPrefix } from '../../nodes/DocumentView';
@@ -121,7 +121,10 @@ 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() {
- return this._layoutElements.filter(ele => ele.bounds && !ele.bounds.z).map(ele => ele.ele);
+ 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>);
+ return renderableEles;
}
@computed get fitToContentVals() {
return {
@@ -579,6 +582,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
ActiveArrowEnd(),
ActiveDash(),
points,
+ ActiveIsInkMask(),
{
title: 'ink stroke',
x: B.x - ActiveInkWidth() / 2,
@@ -1519,6 +1523,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),
})
);
diff --git a/src/client/views/global/globalCssVariables.scss b/src/client/views/global/globalCssVariables.scss
index a14634bdc..c5968d9a7 100644
--- a/src/client/views/global/globalCssVariables.scss
+++ b/src/client/views/global/globalCssVariables.scss
@@ -1,4 +1,4 @@
-@import url("https://fonts.googleapis.com/css2?family=Roboto&display=swap");
+@import url('https://fonts.googleapis.com/css2?family=Roboto&display=swap');
// colors
$white: #ffffff;
$off-white: #fdfdfd;
@@ -16,8 +16,10 @@ $yellow: #f5d747;
$close-red: #e48282;
-$drop-shadow: "#32323215";
+$drop-shadow: '#32323215';
+$INK_MASK_SIZE: 50000;
+$INK_MASK_SIZE_HALF: -25000px;
//padding
$minimum-padding: 4px;
@@ -28,8 +30,7 @@ $large-padding: 32px;
$icon-size: 28px;
// fonts
-$sans-serif: "Roboto",
-sans-serif;
+$sans-serif: 'Roboto', sans-serif;
$large-header: 16px;
$body-text: 12px;
$small-text: 9px;
@@ -54,7 +55,6 @@ $standard-border-radius: 3px;
// shadow
$standard-box-shadow: 0px 3px 4px rgba(0, 0, 0, 0.3);
-
$dashboardselector-height: 32px;
$mainTextInput-zindex: 999; // then text input overlay so that it's context menu will appear over decorations, etc
$docDecorations-zindex: 998; // then doc decorations appear over everything else
@@ -79,4 +79,5 @@ $TREE_BULLET_WIDTH: 20px;
DFLT_IMAGE_NATIVE_DIM: $DFLT_IMAGE_NATIVE_DIM;
LEFT_MENU_WIDTH: $LEFT_MENU_WIDTH;
TREE_BULLET_WIDTH: $TREE_BULLET_WIDTH;
-} \ No newline at end of file
+ INK_MASK_SIZE: $INK_MASK_SIZE;
+}
diff --git a/src/client/views/global/globalCssVariables.scss.d.ts b/src/client/views/global/globalCssVariables.scss.d.ts
index 59c2b3585..76259113c 100644
--- a/src/client/views/global/globalCssVariables.scss.d.ts
+++ b/src/client/views/global/globalCssVariables.scss.d.ts
@@ -1,6 +1,5 @@
-
interface IGlobalScss {
- contextMenuZindex: string; // context menu shows up over everything
+ contextMenuZindex: string; // context menu shows up over everything
SCHEMA_DIVIDER_WIDTH: string;
COLLECTION_BORDER_WIDTH: string;
MINIMIZED_ICON_SIZE: string;
@@ -11,7 +10,8 @@ interface IGlobalScss {
DFLT_IMAGE_NATIVE_DIM: string;
LEFT_MENU_WIDTH: string;
TREE_BULLET_WIDTH: string;
+ INK_MASK_SIZE: number;
}
declare const globalCssVariables: IGlobalScss;
-export = globalCssVariables; \ No newline at end of file
+export = globalCssVariables;
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index e154e8445..78f351f4f 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -38,11 +38,8 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
get displayName() {
return 'CollectionFreeFormDocumentView(' + this.rootDoc.title + ')';
} // this makes mobx trace() statements more descriptive
- get maskCentering() {
- return this.props.Document.isInkMask ? InkingStroke.MaskDim / 2 : 0;
- }
get transform() {
- return `translate(${this.X - this.maskCentering}px, ${this.Y - this.maskCentering}px) rotate(${NumCast(this.Document.jitterRotation, this.props.jitterRotation)}deg)`;
+ return `translate(${this.X}px, ${this.Y}px) rotate(${NumCast(this.Document.jitterRotation, this.props.jitterRotation)}deg)`;
}
get X() {
return this.dataProvider ? this.dataProvider.x : NumCast(this.Document.x);
@@ -194,7 +191,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
PanelHeight: this.panelHeight,
};
const background = this.props.styleProvider?.(this.rootDoc, this.props, StyleProp.BackgroundColor);
- const mixBlendMode = (StrCast(this.layoutDoc.mixBlendMode) as any) || (typeof background === 'string' && background && !background.startsWith('linear') && DashColor(background).alpha() !== 1 ? 'multiply' : undefined);
+ const mixBlendMode = undefined; // (StrCast(this.layoutDoc.mixBlendMode) as any) || (typeof background === 'string' && background && !background.startsWith('linear') && DashColor(background).alpha() !== 1 ? 'multiply' : undefined);
return (
<div
className={'collectionFreeFormDocumentView-container'}
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index f9ef85595..bcc55eab4 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1640,8 +1640,8 @@ export class DocumentView extends React.Component<DocumentViewProps> {
render() {
TraceMobx();
- const xshift = () => (this.props.Document.isInkMask && !this.props.LayoutTemplateString && !this.props.LayoutTemplate?.() ? InkingStroke.MaskDim : Math.abs(this.Xshift) <= 0.001 ? this.props.PanelWidth() : undefined);
- const yshift = () => (this.props.Document.isInkMask && !this.props.LayoutTemplateString && !this.props.LayoutTemplate?.() ? InkingStroke.MaskDim : Math.abs(this.Yshift) <= 0.001 ? this.props.PanelHeight() : undefined);
+ const xshift = () => (Math.abs(this.Xshift) <= 0.001 ? this.props.PanelWidth() : undefined);
+ const yshift = () => (Math.abs(this.Yshift) <= 0.001 ? this.props.PanelHeight() : undefined);
const isPresTreeElement: boolean = this.props.treeViewDoc?.type === DocumentType.PRES;
const isButton: boolean = this.props.Document.type === DocumentType.FONTICON || this.props.Document._viewType === CollectionViewType.Linear;
return (
@@ -1652,7 +1652,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
ref={this.ContentRef}
style={{
transition: this.props.dataTransition,
- position: this.props.Document.isInkMask ? 'absolute' : undefined,
+ //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 d3b95e25a..cb68c1ac3 100644
--- a/src/client/views/nodes/button/FontIconBox.tsx
+++ b/src/client/views/nodes/button/FontIconBox.tsx
@@ -1,6 +1,7 @@
import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@material-ui/core';
+import Color from 'color';
import { action, computed, observable, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import * as React from 'react';
@@ -21,7 +22,7 @@ import { DocComponent } from '../../DocComponent';
import { EditableView } from '../../EditableView';
import { GestureOverlay } from '../../GestureOverlay';
import { Colors } from '../../global/globalEnums';
-import { ActiveFillColor, ActiveInkColor, ActiveInkWidth, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth } from '../../InkingStroke';
+import { ActiveFillColor, ActiveInkColor, ActiveInkWidth, ActiveIsInkMask, SetActiveFillColor, SetActiveInkColor, SetActiveInkWidth, SetActiveIsInkMask } from '../../InkingStroke';
import { InkTranscription } from '../../InkTranscription';
import { StyleProp } from '../../StyleProvider';
import { FieldView, FieldViewProps } from '.././FieldView';
@@ -498,8 +499,6 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
</div>
);
- const buttonText = StrCast(this.rootDoc.buttonText);
-
// TODO:glr Add label of button type
let button: JSX.Element | null = this.defaultButton;
@@ -508,7 +507,7 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
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} />
- {buttonText ? <div className="button-text">{buttonText}</div> : null}
+ {StrCast(this.rootDoc.buttonText) ? <div className="button-text">{StrCast(this.rootDoc.buttonText)}</div> : null}
{label}
</div>
);
@@ -563,11 +562,13 @@ export class FontIconBox extends DocComponent<ButtonProps>() {
break;
}
- return !this.layoutDoc.toolTip || this.type === ButtonType.DropdownList || this.type === ButtonType.ColorButton || this.type === ButtonType.NumberButton || this.type === ButtonType.EditableText ? (
- button
- ) : button !== null ? (
- <Tooltip title={<div className="dash-tooltip">{StrCast(this.layoutDoc.toolTip)}</div>}>{button}</Tooltip>
- ) : null;
+ const retval =
+ !this.layoutDoc.toolTip || this.type === ButtonType.DropdownList || this.type === ButtonType.ColorButton || this.type === ButtonType.NumberButton || this.type === ButtonType.EditableText ? (
+ button
+ ) : button !== null ? (
+ <Tooltip title={<div className="dash-tooltip">{StrCast(this.layoutDoc.toolTip)}</div>}>{button}</Tooltip>
+ ) : null;
+ return retval;
}
}
@@ -861,6 +862,21 @@ ScriptingGlobals.add(function setActiveTool(tool: string, checkResult?: boolean)
});
// toggle: Set overlay status of selected document
+ScriptingGlobals.add(function setIsInkMask(checkResult?: boolean) {
+ const selected = SelectionManager.Docs().lastElement();
+ if (checkResult) {
+ if (selected?.type === DocumentType.INK) {
+ return BoolCast(selected.isInkMask) ? Colors.MEDIUM_BLUE : 'transparent';
+ }
+ return ActiveIsInkMask() ? Colors.MEDIUM_BLUE : 'transparent';
+ }
+ SetActiveIsInkMask(!ActiveIsInkMask());
+ SelectionManager.Docs()
+ .filter(doc => doc.type === DocumentType.INK)
+ .map(doc => (doc.isInkMask = !doc.isInkMask));
+});
+
+// toggle: Set overlay status of selected document
ScriptingGlobals.add(function setFillColor(color?: string, checkResult?: boolean) {
const selected = SelectionManager.Docs().lastElement();
if (checkResult) {
diff --git a/src/client/views/nodes/trails/PresBox.tsx b/src/client/views/nodes/trails/PresBox.tsx
index 3bbdce1e4..627f35e71 100644
--- a/src/client/views/nodes/trails/PresBox.tsx
+++ b/src/client/views/nodes/trails/PresBox.tsx
@@ -313,10 +313,15 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
//it'll also execute the necessary actions if presentation is playing.
public gotoDocument = action((index: number, from?: Doc, group?: boolean) => {
Doc.UnBrushAllDocs();
+
if (index >= 0 && index < this.childDocs.length) {
this.rootDoc._itemIndex = index;
const activeItem: Doc = this.activeItem;
const targetDoc: Doc = this.targetDoc;
+ if (activeItem.presActiveFrame !== undefined) {
+ const context = DocCast(DocCast(activeItem.presentationTargetDoc).context);
+ context && CollectionFreeFormViewChrome.gotoKeyFrame(context, NumCast(activeItem.presActiveFrame));
+ }
if (from?.mediaStopTriggerList && this.layoutDoc.presStatus !== PresStatus.Edit) {
DocListCast(from.mediaStopTriggerList).forEach(this.stopTempMedia);
}
@@ -516,20 +521,26 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
if (tagDoc === this.layoutDoc.presCollection) {
tagDoc.opacity = 1;
} else {
- if (itemIndexes.length > 1 && curDoc.presHideBefore && curInd !== 0) {
- } else if (curDoc.presHideBefore) {
- if (index > this.itemIndex) {
- tagDoc.opacity = 0;
- } else if (index === this.itemIndex || !curDoc.presHideAfter) {
+ if (curDoc.presHideBefore) {
+ if (itemIndexes.length > 1 && curInd !== 0) {
tagDoc.opacity = 1;
+ } else {
+ if (index > this.itemIndex) {
+ tagDoc.opacity = 0;
+ } else if (index === this.itemIndex || !curDoc.presHideAfter) {
+ tagDoc.opacity = 1;
+ }
}
}
- if (itemIndexes.length > 1 && curDoc.presHideAfter && curInd !== itemIndexes.length - 1) {
- } else if (curDoc.presHideAfter) {
- if (index < this.itemIndex) {
- tagDoc.opacity = 0;
- } else if (index === this.itemIndex || !curDoc.presHideBefore) {
+ if (curDoc.presHideAfter) {
+ if (itemIndexes.length > 1 && curInd !== itemIndexes.length - 1) {
tagDoc.opacity = 1;
+ } else {
+ if (index < this.itemIndex) {
+ tagDoc.opacity = 0;
+ } else if (index === this.itemIndex || !curDoc.presHideBefore) {
+ tagDoc.opacity = 1;
+ }
}
}
}
@@ -821,11 +832,6 @@ export class PresBox extends ViewBoxBaseComponent<FieldViewProps>() {
this.gotoDocument(this.childDocs.indexOf(doc), this.activeItem);
if (doc.presPinView || doc.presentationTargetDoc === this.layoutDoc.presCollection) setTimeout(() => this.updateCurrentPresentation(context), 0);
else this.updateCurrentPresentation(context);
-
- if (this.activeItem.presActiveFrame !== undefined) {
- const context = DocCast(DocCast(this.activeItem.presentationTargetDoc).context);
- context && CollectionFreeFormViewChrome.gotoKeyFrame(context, NumCast(this.activeItem.presActiveFrame));
- }
};
//Command click
diff --git a/src/fields/InkField.ts b/src/fields/InkField.ts
index 114d5fc2f..a074098c1 100644
--- a/src/fields/InkField.ts
+++ b/src/fields/InkField.ts
@@ -1,22 +1,21 @@
-import { Bezier } from "bezier-js";
-import { createSimpleSchema, list, object, serializable } from "serializr";
-import { ScriptingGlobals } from "../client/util/ScriptingGlobals";
-import { Deserializable } from "../client/util/SerializationHelper";
-import { Copy, ToScriptString, ToString } from "./FieldSymbols";
-import { ObjectField } from "./ObjectField";
+import { Bezier } from 'bezier-js';
+import { createSimpleSchema, list, object, serializable } from 'serializr';
+import { ScriptingGlobals } from '../client/util/ScriptingGlobals';
+import { Deserializable } from '../client/util/SerializationHelper';
+import { Copy, ToScriptString, ToString } from './FieldSymbols';
+import { ObjectField } from './ObjectField';
// Helps keep track of the current ink tool in use.
export enum InkTool {
- None = "none",
- Pen = "pen",
- Highlighter = "highlighter",
- Eraser = "eraser",
- Stamp = "stamp",
- Write = "write",
- PresentationPin = 'presentationpin'
+ None = 'none',
+ Pen = 'pen',
+ Highlighter = 'highlighter',
+ Eraser = 'eraser',
+ Stamp = 'stamp',
+ Write = 'write',
+ PresentationPin = 'presentationpin',
}
-
// Defines a point in an ink as a pair of x- and y-coordinates.
export interface PointData {
X: number;
@@ -54,15 +53,16 @@ export interface HandleLine {
}
const pointSchema = createSimpleSchema({
- X: true, Y: true
+ X: true,
+ Y: true,
});
const strokeDataSchema = createSimpleSchema({
pathData: list(object(pointSchema)),
- "*": true
+ '*': true,
});
-@Deserializable("ink")
+@Deserializable('ink')
export class InkField extends ObjectField {
@serializable(list(object(strokeDataSchema)))
readonly inkData: InkData;
@@ -85,11 +85,11 @@ export class InkField extends ObjectField {
}
[ToScriptString]() {
- return "new InkField([" + this.inkData.map(i => `{X: ${i.X}, Y: ${i.Y}`) + "])";
+ return 'new InkField([' + this.inkData.map(i => `{X: ${i.X}, Y: ${i.Y}}`) + '])';
}
[ToString]() {
- return "InkField";
+ return 'InkField';
}
}
-ScriptingGlobals.add("InkField", InkField); \ No newline at end of file
+ScriptingGlobals.add('InkField', InkField);