aboutsummaryrefslogtreecommitdiff
path: root/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
diff options
context:
space:
mode:
authorNathan-SR <144961007+Nathan-SR@users.noreply.github.com>2024-03-22 22:11:37 -0400
committerNathan-SR <144961007+Nathan-SR@users.noreply.github.com>2024-03-22 22:11:37 -0400
commit3c5bc5b89c3158c6c1dce02f99aa0c08d24dcb39 (patch)
tree99bed6d83f5a01ff2654cd4fb635ea5c48bcc820 /src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
parent26d7e045c5b0a9a29612e68d976e35c0e7e23d00 (diff)
parenta974aa4e6573c8becf93f78610406747fec14c1c (diff)
Merge branch 'master' into nathan-starter
Diffstat (limited to 'src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx')
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx67
1 files changed, 38 insertions, 29 deletions
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 50b3dbd70..b2fb5848e 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1,6 +1,6 @@
import { Bezier } from 'bezier-js';
import { Colors } from 'browndash-components';
-import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction } from 'mobx';
+import { action, computed, IReactionDisposer, makeObservable, observable, reaction, runInAction, trace } from 'mobx';
import { observer } from 'mobx-react';
import { computedFn } from 'mobx-utils';
import * as React from 'react';
@@ -17,7 +17,7 @@ import { BoolCast, Cast, DocCast, NumCast, ScriptCast, StrCast } from '../../../
import { ImageField } from '../../../../fields/URLField';
import { TraceMobx } from '../../../../fields/util';
import { GestureUtils } from '../../../../pen-gestures/GestureUtils';
-import { aggregateBounds, DashColor, emptyFunction, intersectRect, lightOrDark, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils';
+import { aggregateBounds, DashColor, emptyFunction, intersectRect, lightOrDark, numberValue, OmitKeys, returnFalse, returnZero, setupMoveUpEvents, Utils } from '../../../../Utils';
import { CognitiveServices } from '../../../cognitive_services/CognitiveServices';
import { Docs, DocUtils } from '../../../documents/Documents';
import { CollectionViewType, DocumentType } from '../../../documents/DocumentTypes';
@@ -30,7 +30,7 @@ import { SelectionManager } from '../../../util/SelectionManager';
import { freeformScrollMode } from '../../../util/SettingsManager';
import { SnappingManager } from '../../../util/SnappingManager';
import { Transform } from '../../../util/Transform';
-import { undoBatch, UndoManager } from '../../../util/UndoManager';
+import { undoable, undoBatch, UndoManager } from '../../../util/UndoManager';
import { Timeline } from '../../animationtimeline/Timeline';
import { ContextMenu } from '../../ContextMenu';
import { GestureOverlay } from '../../GestureOverlay';
@@ -159,8 +159,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
? { x: cb[0], y: cb[1], r: cb[2], b: cb[3] }
: aggregateBounds(
this._layoutElements.filter(e => e.bounds?.width && !e.bounds.z).map(e => e.bounds!),
- NumCast(this.layoutDoc._xPadding, 10),
- NumCast(this.layoutDoc._yPadding, 10)
+ NumCast(this.layoutDoc._xPadding, this._props.xPadding ?? 10),
+ NumCast(this.layoutDoc._yPadding, this._props.yPadding ?? 10)
);
}
@computed get nativeWidth() {
@@ -249,7 +249,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
// this search order, for example, allows icons of cropped images to find the panx/pany/zoom on the cropped image's data doc instead of the usual layout doc because the zoom/panX/panY define the cropped image
panX = () => this.freeformData()?.bounds.cx ?? NumCast(this.Document[this.panXFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.freeform_panX, 1));
panY = () => this.freeformData()?.bounds.cy ?? NumCast(this.Document[this.panYFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.freeform_panY, 1));
- zoomScaling = () => this.freeformData()?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], NumCast(Cast(this.Document.resolvedDataDoc, Doc, null)?.[this.scaleFieldKey], 1));
+ zoomScaling = () => this.freeformData()?.scale ?? NumCast(Doc.Layout(this.Document)[this.scaleFieldKey], 1); //, NumCast(DocCast(this.Document.resolvedDataDoc)?.[this.scaleFieldKey], 1));
PanZoomCenterXf = () =>
this._props.isAnnotationOverlay && this.zoomScaling() === 1 ? `` : `translate(${this.cachedCenteringShiftX}px, ${this.cachedCenteringShiftY}px) scale(${this.zoomScaling()}) translate(${-this.panX()}px, ${-this.panY()}px)`;
ScreenToContentsXf = () => this.screenToFreeformContentsXf.copy();
@@ -760,7 +760,6 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
this.onGesture(e, new GestureUtils.GestureEvent(gesture, points, GestureOverlay.getBounds(points), text));
};
- @action
onPointerMove = (e: PointerEvent) => {
if (this.tryDragCluster(e, this._hitCluster)) {
e.stopPropagation(); // we're moving a cluster, so stop propagation and return true to end panning and let the document drag take over
@@ -841,10 +840,14 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (excludeT < startSegmentT || excludeT > docCurveTVal) {
const localStartTVal = startSegmentT - Math.floor(i / 4);
t !== (localStartTVal < 0 ? 0 : localStartTVal) && segment.push(inkSegment.split(localStartTVal < 0 ? 0 : localStartTVal, t));
- segment.length && segments.push(segment);
+ if (segment.length && (Math.abs(segment[0].points[0].x - segment[0].points.lastElement().x) > 0.5 || Math.abs(segment[0].points[0].y - segment[0].points.lastElement().y) > 0.5)) segments.push(segment);
}
// start a new segment from the intersection t value
- segment = tVals.length - 1 === index ? [inkSegment.split(t).right] : [];
+ if (tVals.length - 1 === index) {
+ const split = inkSegment.split(t).right;
+ if (split && (Math.abs(split.points[0].x - split.points.lastElement().x) > 0.5 || Math.abs(split.points[0].y - split.points.lastElement().y) > 0.5)) segment = [split];
+ else segment = [];
+ } else segment = [];
startSegmentT = docCurveTVal;
});
} else {
@@ -1143,23 +1146,29 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
isContentActive = () => this._props.isContentActive();
- @undoBatch
+ /**
+ * Create a new text note of the same style as the one being typed into.
+ * If the text doc is be part of a larger templated doc, the new Doc will be a copy of the templated Doc
+ *
+ * @param fieldProps render props for the text doc being typed into
+ * @param below whether to place the new text Doc below or to the right of the one being typed into.
+ * @returns whether the new text doc was created and added successfully
+ */
+ createTextDocCopy = undoable((fieldProps: FieldViewProps, below: boolean) => {
+ const textDoc = DocCast(fieldProps.Document.rootDocument, fieldProps.Document);
+ const newDoc = Doc.MakeCopy(textDoc, true);
+ newDoc[DocData][Doc.LayoutFieldKey(newDoc, fieldProps.LayoutTemplateString)] = undefined; // the copy should not copy the text contents of it source, just the render style
+ newDoc.x = NumCast(textDoc.x) + (below ? 0 : NumCast(textDoc._width) + 10);
+ newDoc.y = NumCast(textDoc.y) + (below ? NumCast(textDoc._height) + 10 : 0);
+ FormattedTextBox.SetSelectOnLoad(newDoc);
+ FormattedTextBox.DontSelectInitialText = true;
+ return this.addDocument?.(newDoc);
+ }, 'copied text note');
+
onKeyDown = (e: React.KeyboardEvent, fieldProps: FieldViewProps) => {
if ((e.metaKey || e.ctrlKey || e.altKey || fieldProps.Document._createDocOnCR) && ['Tab', 'Enter'].includes(e.key)) {
e.stopPropagation?.();
- const below = !e.altKey && e.key !== 'Tab';
- const layout_fieldKey = StrCast(fieldProps.fieldKey);
- const newDoc = Doc.MakeCopy(fieldProps.Document, true);
- const dataField = fieldProps.Document[Doc.LayoutFieldKey(newDoc)];
- newDoc[DocData][Doc.LayoutFieldKey(newDoc)] = dataField === undefined || Cast(dataField, listSpec(Doc), null)?.length !== undefined ? new List<Doc>([]) : undefined;
- if (below) newDoc.y = NumCast(fieldProps.Document.y) + NumCast(fieldProps.Document._height) + 10;
- else newDoc.x = NumCast(fieldProps.Document.x) + NumCast(fieldProps.Document._width) + 10;
- if (layout_fieldKey !== 'layout' && fieldProps.Document[layout_fieldKey] instanceof Doc) {
- newDoc[layout_fieldKey] = fieldProps.Document[layout_fieldKey];
- }
- newDoc[DocData].text = undefined;
- FormattedTextBox.SetSelectOnLoad(newDoc);
- return this.addDocument?.(newDoc);
+ return this.createTextDocCopy(fieldProps, !e.altKey && e.key !== 'Tab');
}
};
@computed get childPointerEvents() {
@@ -1344,7 +1353,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
renderCutoffProvider = computedFn(
function renderCutoffProvider(this: any, doc: Doc) {
- return !this._renderCutoffData.get(doc[Id] + '');
+ return this.Document.isTemplateDoc ? false : !this._renderCutoffData.get(doc[Id] + '');
}.bind(this)
);
@@ -1408,8 +1417,8 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
return anchor;
};
- @action closeInfo = () => (this.Document._hideInfo = true);
- infoUI = () => (this.Document._hideInfo || this.Document.annotationOn || this._props.renderDepth ? null : <CollectionFreeFormInfoUI Document={this.Document} Freeform={this} close={this.closeInfo} />);
+ @action closeInfo = () => (Doc.IsInfoUIDisabled = true);
+ infoUI = () => (Doc.IsInfoUIDisabled || this.Document.annotationOn || this._props.renderDepth ? null : <CollectionFreeFormInfoUI Document={this.Document} Freeform={this} close={this.closeInfo} />);
componentDidMount() {
this._props.setContentViewBox?.(this);
@@ -1467,7 +1476,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
if (!code.includes('dashDiv')) {
const script = CompileScript(code, { params: { docView: 'any' }, typecheck: false, editable: true });
if (script.compiled) script.run({ this: this.DocumentView?.() });
- } else code && !first && eval(code);
+ } else code && !first && eval?.(code);
},
{ fireImmediately: true }
);
@@ -1648,7 +1657,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
!this._props.isAnnotationOverlay &&
!Doc.noviceMode &&
optionItems.push({ description: (this._showAnimTimeline ? 'Close' : 'Open') + ' Animation Timeline', event: action(() => (this._showAnimTimeline = !this._showAnimTimeline)), icon: 'eye' });
- this._props.renderDepth && optionItems.push({ description: 'Use Background Color as Default', event: () => (Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor)), icon: 'palette' });
+ this._props.renderDepth && optionItems.push({ description: 'Use Background Color as Default', event: () => (Cast(Doc.UserDoc().emptyCollection, Doc, null).backgroundColor = StrCast(this.layoutDoc.backgroundColor)), icon: 'palette' });
this._props.renderDepth && optionItems.push({ description: 'Fit Content Once', event: this.fitContentOnce, icon: 'object-group' });
if (!Doc.noviceMode) {
optionItems.push({ description: (!Doc.NativeWidth(this.layoutDoc) || !Doc.NativeHeight(this.layoutDoc) ? 'Freeze' : 'Unfreeze') + ' Aspect', event: this.toggleNativeDimensions, icon: 'snowflake' });
@@ -1712,7 +1721,7 @@ export class CollectionFreeFormView extends CollectionSubView<Partial<collection
incrementalRender = action(() => {
if (!LightboxView.LightboxDoc || LightboxView.Contains(this.DocumentView?.())) {
const layout_unrendered = this.childDocs.filter(doc => !this._renderCutoffData.get(doc[Id]));
- const loadIncrement = 5;
+ const loadIncrement = this.Document.isTemplateDoc ? Number.MAX_VALUE : 5;
for (var i = 0; i < Math.min(layout_unrendered.length, loadIncrement); i++) {
this._renderCutoffData.set(layout_unrendered[i][Id] + '', true);
}