aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBob Zeleznik <zzzman@gmail.com>2020-06-22 21:07:45 -0400
committerBob Zeleznik <zzzman@gmail.com>2020-06-22 21:07:45 -0400
commitd7dbc15ecc211ab9533c0cffa40227523b6a5831 (patch)
treed777aff174d44f65f5f85a72db1fb7d43edf4ab7 /src
parent6017e76469bd820dabdef4e0cab6fbb6c3a988ad (diff)
made chrome commands fire by clicking bullseye. added commands for freeformview. made backgroundHalo() work diffrently for ink strokes
Diffstat (limited to 'src')
-rw-r--r--src/client/views/InkingStroke.tsx4
-rw-r--r--src/client/views/collections/CollectionViewChromes.tsx32
-rw-r--r--src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx76
-rw-r--r--src/client/views/collections/collectionFreeForm/MarqueeView.tsx1
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx2
-rw-r--r--src/client/views/nodes/DocumentView.tsx1
-rw-r--r--src/client/views/nodes/FieldView.tsx1
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx2
8 files changed, 68 insertions, 51 deletions
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 7e3bd1c17..cdabd213b 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -4,7 +4,7 @@ import { observer } from "mobx-react";
import { documentSchema } from "../../fields/documentSchemas";
import { InkData, InkField, InkTool } from "../../fields/InkField";
import { makeInterface } from "../../fields/Schema";
-import { Cast, StrCast } from "../../fields/Types";
+import { Cast, StrCast, BoolCast } from "../../fields/Types";
import { TraceMobx } from "../../fields/util";
import { CognitiveServices } from "../cognitive_services/CognitiveServices";
import { InteractionUtils } from "../util/InteractionUtils";
@@ -54,7 +54,7 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
const scaleY = (this.props.PanelHeight() - strokeWidth) / (height - strokeWidth);
const strokeColor = StrCast(this.layoutDoc.color, ActiveInkColor());
const points = InteractionUtils.CreatePolyline(data, left, top, strokeColor, strokeWidth, strokeWidth,
- StrCast(this.layoutDoc.strokeBezier, ActiveInkBezierApprox()), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5);
+ StrCast(this.layoutDoc.strokeBezier, ActiveInkBezierApprox()), scaleX, scaleY, "", "none", (this.props.isSelected() || BoolCast(this.props.backgroundHalo?.())) && strokeWidth <= 5);
const hpoints = InteractionUtils.CreatePolyline(data, left, top,
this.props.isSelected() && strokeWidth > 5 ? strokeColor : "transparent", strokeWidth, (strokeWidth + 15),
StrCast(this.layoutDoc.strokeBezier, ActiveInkBezierApprox()), scaleX, scaleY, "", this.props.active() ? "visiblestroke" : "none", false);
diff --git a/src/client/views/collections/CollectionViewChromes.tsx b/src/client/views/collections/CollectionViewChromes.tsx
index 52fb63386..ac7136d4d 100644
--- a/src/client/views/collections/CollectionViewChromes.tsx
+++ b/src/client/views/collections/CollectionViewChromes.tsx
@@ -40,28 +40,41 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
_templateCommand = {
params: ["target", "source"], title: "=> item view",
script: "this.target.childLayout = getDocTemplate(this.source?.[0])",
- immediate: (source: Doc[]) => this.target.childLayout = Doc.getDocTemplate(source?.[0]),
+ immediate: undoBatch((source: Doc[]) => source.length && (this.target.childLayout = Doc.getDocTemplate(source?.[0]))),
initialize: emptyFunction,
};
_narrativeCommand = {
params: ["target", "source"], title: "=> child click view",
script: "this.target.childClickedOpenTemplateView = getDocTemplate(this.source?.[0])",
- immediate: (source: Doc[]) => this.target.childClickedOpenTemplateView = Doc.getDocTemplate(source?.[0]),
+ immediate: undoBatch((source: Doc[]) => source.length && (this.target.childClickedOpenTemplateView = Doc.getDocTemplate(source?.[0]))),
initialize: emptyFunction,
};
_contentCommand = {
- params: ["target", "source"], title: "=> content",
+ params: ["target", "source"], title: "=> clear content",
script: "getProto(this.target).data = copyField(this.source);",
- immediate: (source: Doc[]) => Doc.GetProto(this.target).data = new List<Doc>(source), // Doc.aliasDocs(source),
+ immediate: undoBatch((source: Doc[]) => Doc.GetProto(this.target).data = new List<Doc>(source)), // Doc.aliasDocs(source),
initialize: emptyFunction,
};
_viewCommand = {
- params: ["target"], title: "=> saved view",
+ params: ["target"], title: "=> reset view",
script: "this.target._panX = this.restoredPanX; this.target._panY = this.restoredPanY; this.target.scale = this.restoredScale;",
- immediate: (source: Doc[]) => { this.target._panX = 0; this.target._panY = 0; this.target.scale = 1; },
+ immediate: undoBatch((source: Doc[]) => { this.target._panX = 0; this.target._panY = 0; this.target.scale = 1; }),
initialize: (button: Doc) => { button.restoredPanX = this.target._panX; button.restoredPanY = this.target._panY; button.restoredScale = this.target.scale; },
};
- _freeform_commands = [this._contentCommand, this._templateCommand, this._narrativeCommand, this._viewCommand];
+ _clusterCommand = {
+ params: ["target"], title: "=> fit content",
+ script: "this.target._fitToBox = !this.target._fitToBox;",
+ immediate: undoBatch((source: Doc[]) => this.target._fitToBox = !this.target._fitToBox),
+ initialize: emptyFunction
+ };
+ _fitContentCommand = {
+ params: ["target"], title: "=> toggle clusters",
+ script: "this.target.useClusters = !this.target.useClusters;",
+ immediate: undoBatch((source: Doc[]) => this.target.useClusters = !this.target.useClusters),
+ initialize: emptyFunction
+ };
+
+ _freeform_commands = [this._viewCommand, this._fitContentCommand, this._clusterCommand, this._contentCommand, this._templateCommand, this._narrativeCommand];
_stacking_commands = [this._contentCommand, this._templateCommand];
_masonry_commands = [this._contentCommand, this._templateCommand];
_schema_commands = [this._templateCommand, this._narrativeCommand];
@@ -84,6 +97,7 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
@observable private _currentKey: string = "";
componentDidMount = action(() => {
+ this._currentKey = this._currentKey || (this._buttonizableCommands.length ? this._buttonizableCommands[0]?.title : "");
// chrome status is one of disabled, collapsed, or visible. this determines initial state from document
switch (this.props.CollectionView.props.Document._chromeStatus) {
case "disabled":
@@ -248,7 +262,9 @@ export class CollectionViewBaseChrome extends React.Component<CollectionViewChro
DragManager.StartButtonDrag([this._commandRef.current!], c.script, c.title,
{ target: this.props.CollectionView.props.Document }, c.params, c.initialize, e.clientX, e.clientY));
return true;
- }, emptyFunction, emptyFunction);
+ }, emptyFunction, () => {
+ this._buttonizableCommands.filter(c => c.title === this._currentKey).map(c => c.immediate([]));
+ });
}
@computed get templateChrome() {
diff --git a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
index 960b6efef..ac1456970 100644
--- a/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
+++ b/src/client/views/collections/collectionFreeForm/CollectionFreeFormView.tsx
@@ -1128,6 +1128,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
this.props.Document[this.scaleFieldKey] = Math.max(1, NumCast(this.props.Document[this.scaleFieldKey]));
}
+ this.Document.useClusters && !this._clusterSets.length && this.childDocs.length && this.updateClusters(true);
return elements;
}
@@ -1197,59 +1198,58 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
onContextMenu = (e: React.MouseEvent) => {
if (this.props.annotationsKey) return;
- !this.props.isAnnotationOverlay && ContextMenu.Instance.addItem({
- description: (this._timelineVisible ? "Close" : "Open") + " Animation Timeline", event: action(() => {
- this._timelineVisible = !this._timelineVisible;
- }), icon: this._timelineVisible ? faEyeSlash : faEye
- });
-
const appearance = ContextMenu.Instance.findByDescription("Appearance...");
const appearanceItems = appearance && "subitems" in appearance ? appearance.subitems : [];
appearanceItems.push({ description: "reset view", event: () => { this.props.Document._panX = this.props.Document._panY = 0; this.props.Document[this.scaleFieldKey] = 1; }, icon: "compress-arrows-alt" });
appearanceItems.push({ description: `${this.fitToContent ? "Unset" : "Set"} Fit To Container`, event: () => this.Document._fitToBox = !this.fitToContent, icon: !this.fitToContent ? "expand-arrows-alt" : "compress-arrows-alt" });
appearanceItems.push({ description: `${this.Document.useClusters ? "Uncluster" : "Use Clusters"}`, event: () => this.updateClusters(!this.Document.useClusters), icon: "braille" });
- appearanceItems.push({ description: "Use Background Color as Default", event: () => Cast(Doc.UserDoc().emptyCollection, Doc, null)!._backgroundColor = StrCast(this.layoutDoc._backgroundColor), icon: "palette" });
+ appearanceItems.push({ description: "Use Background Color as Default", event: () => Cast(Doc.UserDoc().emptyCollection, Doc, null)._backgroundColor = StrCast(this.layoutDoc._backgroundColor), icon: "palette" });
!appearance && ContextMenu.Instance.addItem({ description: "Appearance...", subitems: appearanceItems, icon: "eye" });
const options = ContextMenu.Instance.findByDescription("Options...");
const optionItems = options && "subitems" in options ? options.subitems : [];
- optionItems.push({ description: "toggle snap line display", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" });
- !Doc.UserDoc().noviceMode && optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" });
- this.props.ContainingCollectionView && optionItems.push({ description: "Promote Collection", event: this.promoteCollection, icon: "table" });
+ !this.props.isAnnotationOverlay &&
+ optionItems.push({ description: (this.showTimeline ? "Close" : "Open") + " Animation Timeline", event: action(() => this.showTimeline = !this.showTimeline), icon: faEye });
+ this.props.ContainingCollectionView &&
+ optionItems.push({ description: "Promote Collection", event: this.promoteCollection, icon: "table" });
+ optionItems.push({ description: (Doc.UserDoc().showSnapLines ? "Hide" : "Show") + " snap lines", event: () => Doc.UserDoc().showSnapLines = !Doc.UserDoc().showSnapLines, icon: "compress-arrows-alt" });
optionItems.push({ description: this.layoutDoc._lockedTransform ? "Unlock Transform" : "Lock Transform", event: this.toggleLockTransform, icon: this.layoutDoc._lockedTransform ? "unlock" : "lock" });
optionItems.push({ description: "Arrange contents in grid", event: this.layoutDocsInGrid, icon: "table" });
- !Doc.UserDoc().noviceMode && optionItems.push({
- description: "Import document", icon: "upload", event: ({ x, y }) => {
- const input = document.createElement("input");
- input.type = "file";
- input.accept = ".zip";
- input.onchange = async _e => {
- const upload = Utils.prepend("/uploadDoc");
- const formData = new FormData();
- const file = input.files && input.files[0];
- if (file) {
- formData.append('file', file);
- formData.append('remap', "true");
- const response = await fetch(upload, { method: "POST", body: formData });
- const json = await response.json();
- if (json !== "error") {
- const doc = await DocServer.GetRefField(json);
- if (doc instanceof Doc) {
- const [xx, yy] = this.props.ScreenToLocalTransform().transformPoint(x, y);
- doc.x = xx, doc.y = yy;
- this.props.addDocument?.(doc);
+ if (!Doc.UserDoc().noviceMode) {
+ optionItems.push({ description: (!this.layoutDoc._nativeWidth || !this.layoutDoc._nativeHeight ? "Freeze" : "Unfreeze") + " Aspect", event: this.toggleNativeDimensions, icon: "snowflake" });
+ optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" });
+ optionItems.push({
+ description: "Import document", icon: "upload", event: ({ x, y }) => {
+ const input = document.createElement("input");
+ input.type = "file";
+ input.accept = ".zip";
+ input.onchange = async _e => {
+ const upload = Utils.prepend("/uploadDoc");
+ const formData = new FormData();
+ const file = input.files && input.files[0];
+ if (file) {
+ formData.append('file', file);
+ formData.append('remap', "true");
+ const response = await fetch(upload, { method: "POST", body: formData });
+ const json = await response.json();
+ if (json !== "error") {
+ const doc = await DocServer.GetRefField(json);
+ if (doc instanceof Doc) {
+ const [xx, yy] = this.props.ScreenToLocalTransform().transformPoint(x, y);
+ doc.x = xx, doc.y = yy;
+ this.props.addDocument?.(doc);
+ }
}
}
- }
- };
- input.click();
- }
- });
- !Doc.UserDoc().noviceMode && optionItems.push({ description: `${this.Document._LODdisable ? "Enable LOD" : "Disable LOD"}`, event: () => this.Document._LODdisable = !this.Document._LODdisable, icon: "table" });
+ };
+ input.click();
+ }
+ });
+ }
!options && ContextMenu.Instance.addItem({ description: "Options...", subitems: optionItems, icon: "eye" });
}
- @observable _timelineVisible = false;
+ @observable showTimeline = false;
intersectRect(r1: { left: number, top: number, width: number, height: number },
r2: { left: number, top: number, width: number, height: number }) {
@@ -1350,7 +1350,7 @@ export class CollectionFreeFormView extends CollectionSubView<PanZoomDocument, P
zoomScaling={this.zoomScaling} panX={this.panX} panY={this.panY}>
{this.children}
</CollectionFreeFormViewPannableContents>
- {this._timelineVisible ? <Timeline ref={this._timelineRef} {...this.props} /> : (null)}
+ {this.showTimeline ? <Timeline ref={this._timelineRef} {...this.props} /> : (null)}
</MarqueeView>;
}
diff --git a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
index 23efeec8d..1bc7c6fb5 100644
--- a/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
+++ b/src/client/views/collections/collectionFreeForm/MarqueeView.tsx
@@ -741,7 +741,6 @@ export class MarqueeView extends React.Component<SubCollectionViewProps & Marque
return <div className="marqueeView"
style={{ overflow: StrCast(this.props.Document._overflow), cursor: MarqueeView.DragMarquee && this ? "crosshair" : "hand" }}
onDragOver={e => e.preventDefault()}
- onPaste={this.paste}
onScroll={(e) => e.currentTarget.scrollTop = e.currentTarget.scrollLeft = 0} onClick={this.onClick} onPointerDown={this.onPointerDown}>
{this._visible ? this.marqueeDiv : null}
{this.props.children}
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index f934945a6..404d69730 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -144,7 +144,7 @@ export class CollectionFreeFormDocumentView extends DocComponent<CollectionFreeF
boxShadow:
this.Opacity === 0 ? undefined : // if it's not visible, then no shadow
this.layoutDoc.z ? `#9c9396 ${StrCast(this.layoutDoc.boxShadow, "10px 10px 0.9vw")}` : // if it's a floating doc, give it a big shadow
- this.props.backgroundHalo?.() ? (`${this.props.backgroundColor?.(this.props.Document)} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(this.layoutDoc.isBackground ? 100 : 50) / this.props.ContentScaling()}px`)}`) : // if it's just in a cluster, make the shadown roughly match the cluster border extent
+ this.props.backgroundHalo?.() && this.props.Document.type !== DocumentType.INK ? (`${this.props.backgroundColor?.(this.props.Document)} ${StrCast(this.layoutDoc.boxShadow, `0vw 0vw ${(this.layoutDoc.isBackground ? 100 : 50) / this.props.ContentScaling()}px`)}`) : // if it's just in a cluster, make the shadown roughly match the cluster border extent
this.layoutDoc.isBackground ? undefined : // if it's a background & has a cluster color, make the shadow spread really big
StrCast(this.layoutDoc.boxShadow, ""),
borderRadius: StrCast(Doc.Layout(this.layoutDoc).borderRounding),
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 71cb18e08..4e4c859ef 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1007,6 +1007,7 @@ export class DocumentView extends DocComponent<DocumentViewProps, Document>(Docu
LayoutTemplate={this.props.LayoutTemplate}
makeLink={this.makeLink}
rootSelected={this.rootSelected}
+ backgroundHalo={this.props.backgroundHalo}
dontRegisterView={this.props.dontRegisterView}
fitToBox={this.props.fitToBox}
LibraryPath={this.props.LibraryPath}
diff --git a/src/client/views/nodes/FieldView.tsx b/src/client/views/nodes/FieldView.tsx
index 305c04a90..c57738361 100644
--- a/src/client/views/nodes/FieldView.tsx
+++ b/src/client/views/nodes/FieldView.tsx
@@ -27,6 +27,7 @@ export interface FieldViewProps {
LibraryPath: Doc[];
onClick?: ScriptField;
dropAction: dropActionType;
+ backgroundHalo?: () => boolean;
docFilters: () => string[];
isSelected: (outsideReaction?: boolean) => boolean;
select: (isCtrlPressed: boolean) => void;
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 5e0585169..2a019ada7 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -452,7 +452,7 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<(FieldViewProp
appearanceItems.push({
description: "Convert to be a template style", event: () => {
if (!this.layoutDoc.isTemplateDoc) {
- const title = StrCast(this.rootDoc.title)
+ const title = StrCast(this.rootDoc.title);
this.rootDoc.title = "text";
this.rootDoc.isTemplateDoc = makeTemplate(this.rootDoc, true, title);
} else {