aboutsummaryrefslogtreecommitdiff
path: root/src/client/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/util')
-rw-r--r--src/client/util/CaptureManager.tsx2
-rw-r--r--src/client/util/CurrentUserUtils.ts14
-rw-r--r--src/client/util/DocumentManager.ts12
-rw-r--r--src/client/util/DragManager.ts26
-rw-r--r--src/client/util/LinkManager.ts32
-rw-r--r--src/client/util/SelectionManager.ts63
-rw-r--r--src/client/util/SettingsManager.tsx12
-rw-r--r--src/client/util/SnappingManager.ts14
-rw-r--r--src/client/util/Transform.ts73
9 files changed, 147 insertions, 101 deletions
diff --git a/src/client/util/CaptureManager.tsx b/src/client/util/CaptureManager.tsx
index f42336ee7..8a4f37121 100644
--- a/src/client/util/CaptureManager.tsx
+++ b/src/client/util/CaptureManager.tsx
@@ -73,7 +73,7 @@ export class CaptureManager extends React.Component<{}> {
<div
className="save"
onClick={() => {
- LightboxView.SetLightboxDoc(this._document);
+ LightboxView.Instance.SetLightboxDoc(this._document);
this.close();
}}>
Save
diff --git a/src/client/util/CurrentUserUtils.ts b/src/client/util/CurrentUserUtils.ts
index 87ee1b252..ac506e2d6 100644
--- a/src/client/util/CurrentUserUtils.ts
+++ b/src/client/util/CurrentUserUtils.ts
@@ -110,7 +110,7 @@ export class CurrentUserUtils {
const tempClicks = DocCast(doc[field]);
const reqdClickOpts:DocumentOptions = {_width: 300, _height:200, isSystem: true};
const reqdTempOpts:{opts:DocumentOptions, script: string}[] = [
- { opts: { title: "Open In Target", targetScriptKey: "onChildClick"}, script: "docCast(documentView?.props.docViewPath().lastElement()?.rootDoc.target).then((target) => target && (target.proto.data = new List([self])))"},
+ { opts: { title: "Open In Target", targetScriptKey: "onChildClick"}, script: "docCastAsync(documentView?.props.docViewPath().lastElement()?.rootDoc.target).then((target) => target && (target.proto.data = new List([self])))"},
{ opts: { title: "Open Detail On Right", targetScriptKey: "onChildDoubleClick"}, script: `openDoc(self.doubleClickView.${OpenWhere.addRight})`}];
const reqdClickList = reqdTempOpts.map(opts => {
const allOpts = {...reqdClickOpts, ...opts.opts};
@@ -339,7 +339,7 @@ export class CurrentUserUtils {
/// returns descriptions needed to buttons for the left sidebar to open up panes displaying different collections of documents
static leftSidebarMenuBtnDescriptions(doc: Doc):{title:string, target:Doc, icon:string, toolTip: string, scripts:{[key:string]:any}, funcs?:{[key:string]:any}, hidden?: boolean}[] {
- const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())";
+ const badgeValue = "((len) => len && len !== '0' ? len: undefined)(docList(self.target?.data).filter(doc => !docList(self.target.viewed).includes(doc)).length.toString())";
const getActiveDashTrails = "Doc.ActiveDashboard?.myTrails";
return [
{ title: "Dashboards", toolTip: "Dashboards", target: this.setupDashboards(doc, "myDashboards"), ignoreClick: true, icon: "desktop", funcs: {hidden: "IsNoviceMode()"} },
@@ -655,13 +655,13 @@ export class CurrentUserUtils {
{ title: "Under", toolTip: "Underline (Ctrl+U)", btnType: ButtonType.ToggleButton, icon: "underline", toolType:"underline",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
{ title: "Bullets", toolTip: "Bullet List", btnType: ButtonType.ToggleButton, icon: "list", toolType:"bullet", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
{ title: "#", toolTip: "Number List", btnType: ButtonType.ToggleButton, icon: "list-ol", toolType:"decimal", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
+ { title: "Vcenter", toolTip: "Vertical center", btnType: ButtonType.ToggleButton, icon: "pallet", toolType:"vcent", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
{ title: "Align", toolTip: "Alignment", btnType: ButtonType.MultiToggleButton, toolType:"alignment", ignoreClick: true,
subMenu: [
{ title: "Left", toolTip: "Left align (Cmd-[)", btnType: ButtonType.ToggleButton, icon: "align-left", toolType:"left", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}' }},
{ title: "Center", toolTip: "Center align (Cmd-\\)",btnType: ButtonType.ToggleButton, icon: "align-center",toolType:"center",ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
{ title: "Right", toolTip: "Right align (Cmd-])", btnType: ButtonType.ToggleButton, icon: "align-right", toolType:"right", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'} },
- ]
- },
+ ]},
{ title: "Dictate", toolTip: "Dictate", btnType: ButtonType.ToggleButton, icon: "microphone", toolType:"dictation", ignoreClick: true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}},
{ title: "NoLink", toolTip: "Auto Link", btnType: ButtonType.ToggleButton, icon: "link", toolType:"noAutoLink", expertMode:true, scripts: {onClick: '{ return toggleCharStyle(self.toolType, _readOnly_);}'}, funcs: {hidden: 'IsNoviceMode()'}},
// { title: "Strikethrough", tooltip: "Strikethrough", btnType: ButtonType.ToggleButton, icon: "strikethrough", scripts: {onClick:: 'toggleStrikethrough()'}},
@@ -793,11 +793,6 @@ export class CurrentUserUtils {
return DocUtils.AssignDocField(doc, field, (opts, items) => this.linearButtonList(opts, items??[]), dockBtnsReqdOpts, btns);
}
- /// collection of documents rendered in the overlay layer above all tabs and other UI
- static setupOverlays(doc: Doc, field = "myOverlayDocs") {
- return DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.FreeformDocument([], opts), { title: "overlay documents", backgroundColor: "#aca3a6", isSystem: true });
- }
-
static setupPublished(doc:Doc, field = "myPublishedDocs") {
return DocUtils.AssignDocField(doc, field, (opts) => Docs.Create.TreeDocument([], opts), { title: "published docs", backgroundColor: "#aca3a6", isSystem: true });
}
@@ -901,7 +896,6 @@ export class CurrentUserUtils {
this.setupSharedDocs(doc, sharingDocumentId); // sets up the right sidebar collection for mobile upload documents and sharing
this.setupDefaultIconTemplates(doc); // creates a set of icon templates triggered by the document deoration icon
this.setupActiveMobileMenu(doc); // sets up the current mobile menu for Dash Mobile
- this.setupOverlays(doc); // sets up the overlay panel where documents and other widgets can be added to float over the rest of the dashboard
this.setupPublished(doc); // sets up the list doc of all docs that have been published (meaning that they can be auto-linked by typing their title into another text box)
this.setupContextMenuButtons(doc); // set up the row of buttons at the top of the dashboard that change depending on what is selected
this.setupTopbarButtons(doc);
diff --git a/src/client/util/DocumentManager.ts b/src/client/util/DocumentManager.ts
index 7cc8afaa6..3c59a8060 100644
--- a/src/client/util/DocumentManager.ts
+++ b/src/client/util/DocumentManager.ts
@@ -13,6 +13,7 @@ import { LightboxView } from '../views/LightboxView';
import { DocFocusOptions, DocumentView, DocumentViewInternal, OpenWhere, OpenWhereMod } from '../views/nodes/DocumentView';
import { KeyValueBox } from '../views/nodes/KeyValueBox';
import { LinkAnchorBox } from '../views/nodes/LinkAnchorBox';
+import { LoadingBox } from '../views/nodes/LoadingBox';
import { PresBox } from '../views/nodes/trails';
import { ScriptingGlobals } from './ScriptingGlobals';
import { SelectionManager } from './SelectionManager';
@@ -40,8 +41,8 @@ export class DocumentManager {
//private constructor so no other class can create a nodemanager
private constructor() {
- if (!Doc.CurrentlyLoading) Doc.CurrentlyLoading = [];
- observe(Doc.CurrentlyLoading, change => {
+ if (!LoadingBox.CurrentlyLoading) LoadingBox.CurrentlyLoading = [];
+ observe(LoadingBox.CurrentlyLoading, change => {
// watch CurrentlyLoading-- when something is loaded, it's removed from the list and we have to update its icon if it were iconified since LoadingBox icons are different than the media they become
switch (change.type as any) {
case 'update':
@@ -306,7 +307,7 @@ export class DocumentManager {
focused = focused || (nextFocus === undefined ? false : true); // keep track of whether focusing on a view needed to actually change anything
const { childDocView, viewSpec } = await iterator(docView);
if (!childDocView) return { viewSpec: options.anchorDoc ?? viewSpec ?? docView.rootDoc, docView, contextView, focused };
- contextView = docView;
+ contextView = options.anchorDoc?.layout_unrendered ? childDocView : docView;
docView = childDocView;
}
};
@@ -326,14 +327,15 @@ export class DocumentManager {
if (options.zoomTextSelections && Doc.UnhighlightTimer && contextView && viewSpec.text_html) {
// if the docView is a text anchor, the contextView is the PDF/Web/Text doc
- contextView.htmlOverlayEffect = StrCast(options?.effect?.presentation_effect, StrCast(options?.effect?.followLinkAnimEffect));
+ contextView.htmlOverlayEffect = options.effect;
+ contextView.textHtmlOverlayTime = options.zoomTime;
contextView.textHtmlOverlay = StrCast(targetDoc.text_html);
DocumentManager._overlayViews.add(contextView);
}
Doc.AddUnHighlightWatcher(() => {
docView.rootDoc[Animation] = undefined;
DocumentManager.removeOverlayViews();
- contextView && (contextView.htmlOverlayEffect = '');
+ contextView && (contextView.htmlOverlayEffect = undefined);
});
}
}
diff --git a/src/client/util/DragManager.ts b/src/client/util/DragManager.ts
index 8d8975763..6e4de252d 100644
--- a/src/client/util/DragManager.ts
+++ b/src/client/util/DragManager.ts
@@ -8,6 +8,7 @@ import { ScriptCast, StrCast } from '../../fields/Types';
import { emptyFunction, Utils } from '../../Utils';
import { Docs, DocUtils } from '../documents/Documents';
import * as globalCssVariables from '../views/global/globalCssVariables.scss';
+import { CollectionFreeFormDocumentView } from '../views/nodes/CollectionFreeFormDocumentView';
import { DocumentView } from '../views/nodes/DocumentView';
import { ScriptingGlobals } from './ScriptingGlobals';
import { SelectionManager } from './SelectionManager';
@@ -57,7 +58,7 @@ export function SetupDrag(_reference: React.RefObject<HTMLElement>, docFunc: ()
export namespace DragManager {
let dragDiv: HTMLDivElement;
let dragLabel: HTMLDivElement;
- export let StartWindowDrag: Opt<(e: { pageX: number; pageY: number }, dragDocs: Doc[], finishDrag?: (aborted: boolean) => void) => void>;
+ export let StartWindowDrag: Opt<(e: { pageX: number; pageY: number }, dragDocs: Doc[], finishDrag?: (aborted: boolean) => void) => boolean>;
export let CompleteWindowDrag: Opt<(aborted: boolean) => void>;
export function Root() {
@@ -198,7 +199,7 @@ export namespace DragManager {
};
const finishDrag = async (e: DragCompleteEvent) => {
const docDragData = e.docDragData;
- setTimeout(() => dragData.draggedViews.forEach(view => view.props.CollectionFreeFormDocumentView?.().dragEnding()));
+ setTimeout(() => dragData.draggedViews.forEach(view => view.props.dragEnding?.()));
onDropCompleted?.(e); // glr: optional additional function to be called - in this case with presentation trails
if (docDragData && !docDragData.droppedDocuments.length) {
docDragData.dropAction = dragData.userDropAction || dragData.dropAction;
@@ -234,7 +235,7 @@ export namespace DragManager {
};
dragData.draggedDocuments.map(d => d.dragFactory); // does this help? trying to make sure the dragFactory Doc is loaded
StartDrag(eles, dragData, downX, downY, options, finishDrag);
- dragData.draggedViews.forEach(view => view.props.CollectionFreeFormDocumentView?.().dragStarting());
+ dragData.draggedViews.forEach(view => view.props.dragStarting?.());
return true;
}
@@ -360,11 +361,18 @@ export namespace DragManager {
const docsToDrag = dragData instanceof DocumentDragData ? dragData.draggedDocuments : dragData instanceof AnchorAnnoDragData ? [dragData.dragDocument] : [];
const dragElements = eles.map(ele => {
// bcz: very hacky -- if dragged element is a freeForm view with a rotation, then extract the rotation in order to apply it to the dragged element
- let useDim = false; // if doc is rotated by freeformview, then the dragged elements width and height won't reflect the unrotated dimensions, so we need to rely on the element knowing its own width/height. \
+ // bcz: used to be false, but that made dragging collection w/ native dim's not work...
+ let useDim = true; // if doc is rotated by freeformview, then the dragged elements width and height won't reflect the unrotated dimensions, so we need to rely on the element knowing its own width/height. \
// if the parent isn't a freeform view, then the element's width and height are presumed to match the acutal doc's dimensions (eg, dragging from import sidebar menu)
- if (ele?.parentElement?.parentElement?.parentElement?.className === 'collectionFreeFormDocumentView-container') {
- ele = ele.parentElement.parentElement.parentElement;
- rot.push(Number(ele.style.transform.replace(/.*rotate\(([-0-9.e]*)deg\).*/, '$1') || 0));
+ let rotation: number | undefined;
+ for (let parEle: HTMLElement | null | undefined = ele.parentElement; parEle; parEle = parEle?.parentElement) {
+ if (parEle.className === CollectionFreeFormDocumentView.CollectionFreeFormDocViewClassName) {
+ rotation = (rotation ?? 0) + Number(parEle.style.transform.replace(/.*rotate\(([-0-9.e]*)deg\).*/, '$1') || 0);
+ }
+ parEle = parEle.parentElement;
+ }
+ if (rotation !== undefined) {
+ rot.push(rotation);
} else {
useDim = true;
rot.push(0);
@@ -475,7 +483,7 @@ export namespace DragManager {
};
const cleanupDrag = action((undo: boolean) => {
- (dragData as DocumentDragData).draggedViews?.forEach(view => view.props.CollectionFreeFormDocumentView?.().dragEnding());
+ (dragData as DocumentDragData).draggedViews?.forEach(view => view.props.dragEnding?.());
hideDragShowOriginalElements(false);
document.removeEventListener('pointermove', moveHandler, true);
document.removeEventListener('pointerup', upHandler, true);
@@ -490,7 +498,7 @@ export namespace DragManager {
if (dragData instanceof DocumentDragData) {
dragData.userDropAction = e.ctrlKey && e.altKey ? 'copy' : e.ctrlKey ? 'embed' : dragData.defaultDropAction;
}
- if (((e.target as any)?.className === 'lm_tabs' || (e.target as any)?.className === 'lm_header' || e?.shiftKey) && dragData.draggedDocuments.length === 1) {
+ if (((e.target as any)?.className === 'lm_tabs' || (e.target as any)?.className === 'lm_header') && dragData.draggedDocuments.length === 1) {
if (!startWindowDragTimer) {
startWindowDragTimer = setTimeout(async () => {
startWindowDragTimer = undefined;
diff --git a/src/client/util/LinkManager.ts b/src/client/util/LinkManager.ts
index ba53a760f..608184596 100644
--- a/src/client/util/LinkManager.ts
+++ b/src/client/util/LinkManager.ts
@@ -197,14 +197,32 @@ export class LinkManager {
}
// finds the opposite anchor of a given anchor in a link
- //TODO This should probably return undefined if there isn't an opposite anchor
- //TODO This should also await the return value of the anchor so we don't filter out promises
public static getOppositeAnchor(linkDoc: Doc, anchor: Doc): Doc | undefined {
- const a1 = Cast(linkDoc.link_anchor_1, Doc, null);
- const a2 = Cast(linkDoc.link_anchor_2, Doc, null);
- if (Doc.AreProtosEqual(DocCast(anchor.annotationOn, anchor), DocCast(a1?.annotationOn, a1))) return a2;
- if (Doc.AreProtosEqual(DocCast(anchor.annotationOn, anchor), DocCast(a2?.annotationOn, a2))) return a1;
- if (Doc.AreProtosEqual(anchor, linkDoc)) return linkDoc;
+ const id = LinkManager.anchorIndex(linkDoc, anchor);
+ const a1 = DocCast(linkDoc.link_anchor_1);
+ const a2 = DocCast(linkDoc.link_anchor_2);
+ return id === '1' ? a2 : id === '2' ? a1 : id === '0' ? linkDoc : undefined;
+ // if (Doc.AreProtosEqual(DocCast(anchor.annotationOn, anchor), DocCast(a1?.annotationOn, a1))) return a2;
+ // if (Doc.AreProtosEqual(DocCast(anchor.annotationOn, anchor), DocCast(a2?.annotationOn, a2))) return a1;
+ // if (Doc.AreProtosEqual(anchor, linkDoc)) return linkDoc;
+ }
+ public static anchorIndex(linkDoc: Doc, anchor: Doc) {
+ const a1 = DocCast(linkDoc.link_anchor_1);
+ const a2 = DocCast(linkDoc.link_anchor_2);
+ if (linkDoc.link_matchEmbeddings) {
+ return [a2, a2.annotationOn].includes(anchor) ? '2' : '1';
+ }
+ if (Doc.AreProtosEqual(DocCast(anchor.annotationOn, anchor), DocCast(a1?.annotationOn, a1))) return '1';
+ if (Doc.AreProtosEqual(DocCast(anchor.annotationOn, anchor), DocCast(a2?.annotationOn, a2))) return '2';
+ if (Doc.AreProtosEqual(anchor, linkDoc)) return '0';
+
+ // const a1 = DocCast(linkDoc.link_anchor_1);
+ // const a2 = DocCast(linkDoc.link_anchor_2);
+ // if (linkDoc.link_matchEmbeddings) {
+ // return [a2, a2.annotationOn].includes(anchor) ? '2' : '1';
+ // }
+ // if (Doc.AreProtosEqual(a2, anchor) || Doc.AreProtosEqual(a2.annotationOn as Doc, anchor)) return '2';
+ // return Doc.AreProtosEqual(a1, anchor) || Doc.AreProtosEqual(a1.annotationOn as Doc, anchor) ? '1' : '2';
}
}
diff --git a/src/client/util/SelectionManager.ts b/src/client/util/SelectionManager.ts
index d0f66d124..f7e6fa2dc 100644
--- a/src/client/util/SelectionManager.ts
+++ b/src/client/util/SelectionManager.ts
@@ -1,6 +1,6 @@
-import { action, observable, ObservableMap } from 'mobx';
-import { computedFn } from 'mobx-utils';
+import { action, observable } from 'mobx';
import { Doc, Opt } from '../../fields/Doc';
+import { DocViews } from '../../fields/DocSymbols';
import { List } from '../../fields/List';
import { listSpec } from '../../fields/Schema';
import { Cast, DocCast } from '../../fields/Types';
@@ -12,9 +12,8 @@ import { UndoManager } from './UndoManager';
export namespace SelectionManager {
class Manager {
- @observable IsDragging: boolean = false;
- SelectedViewsMap: ObservableMap<DocumentView, Doc> = new ObservableMap();
@observable SelectedViews: DocumentView[] = [];
+ @observable IsDragging: boolean = false;
@observable SelectedSchemaDocument: Doc | undefined;
@action
@@ -22,29 +21,18 @@ export namespace SelectionManager {
manager.SelectedSchemaDocument = doc;
}
@action
- SelectView(docView: DocumentView, ctrlPressed: boolean): void {
- // if doc is not in SelectedDocuments, add it
- if (!manager.SelectedViewsMap.get(docView)) {
- if (!ctrlPressed) {
- this.DeselectAll();
- }
-
+ SelectView(docView: DocumentView, extendSelection: boolean): void {
+ if (!docView.SELECTED) {
+ if (!extendSelection) this.DeselectAll();
manager.SelectedViews.push(docView);
- manager.SelectedViewsMap.set(docView, docView.rootDoc);
+ docView.SELECTED = true;
docView.props.whenChildContentsActiveChanged(true);
- } else if (!ctrlPressed && (Array.from(manager.SelectedViewsMap.entries()).length > 1 || manager.SelectedSchemaDocument)) {
- Array.from(manager.SelectedViewsMap.keys()).map(dv => dv !== docView && dv.props.whenChildContentsActiveChanged(false));
- manager.SelectedSchemaDocument = undefined;
- manager.SelectedViews.length = 0;
- manager.SelectedViewsMap.clear();
- manager.SelectedViews.push(docView);
- manager.SelectedViewsMap.set(docView, docView.rootDoc);
}
}
@action
DeselectView(docView?: DocumentView): void {
- if (docView && manager.SelectedViewsMap.get(docView)) {
- manager.SelectedViewsMap.delete(docView);
+ if (docView && manager.SelectedViews.includes(docView)) {
+ docView.SELECTED = false;
manager.SelectedViews.splice(manager.SelectedViews.indexOf(docView), 1);
docView.props.whenChildContentsActiveChanged(false);
}
@@ -54,8 +42,10 @@ export namespace SelectionManager {
LinkManager.currentLink = undefined;
LinkManager.currentLinkAnchor = undefined;
manager.SelectedSchemaDocument = undefined;
- Array.from(manager.SelectedViewsMap.keys()).forEach(dv => dv.props.whenChildContentsActiveChanged(false));
- manager.SelectedViewsMap.clear();
+ manager.SelectedViews.forEach(dv => {
+ dv.SELECTED = false;
+ dv.props.whenChildContentsActiveChanged(false);
+ });
manager.SelectedViews.length = 0;
}
}
@@ -74,45 +64,24 @@ export namespace SelectionManager {
manager.SelectSchemaViewDoc(document);
}
- const IsSelectedCache = computedFn(function isSelected(doc: DocumentView) {
- // wrapping get() in a computedFn only generates mobx() invalidations when the return value of the function for the specific get parameters has changed
- return manager.SelectedViewsMap.get(doc) ? true : false;
- });
- // computed functions, such as used in IsSelected generate errors if they're called outside of a
- // reaction context. Specifying the context with 'outsideReaction' allows an efficiency feature
- // to avoid unnecessary mobx invalidations when running inside a reaction.
- export function IsSelected(doc: DocumentView | undefined, outsideReaction?: boolean): boolean {
- return !doc
- ? false
- : outsideReaction
- ? manager.SelectedViewsMap.get(doc)
- ? true
- : false // get() accesses a hashtable -- setting anything in the hashtable generates a mobx invalidation for every get()
- : IsSelectedCache(doc);
+ export function IsSelected(doc?: Doc): boolean {
+ return Array.from(doc?.[DocViews] ?? []).some(dv => dv?.SELECTED);
}
export function DeselectAll(except?: Doc): void {
- let found: DocumentView | undefined = undefined;
- if (except) {
- for (const view of Array.from(manager.SelectedViewsMap.keys())) {
- if (view.props.Document === except) found = view;
- }
- }
-
+ const found = manager.SelectedViews.find(dv => dv.Document === except);
manager.DeselectAll();
if (found) manager.SelectView(found, false);
}
export function Views(): Array<DocumentView> {
return manager.SelectedViews;
- // Array.from(manager.SelectedViewsMap.keys()); //.filter(dv => manager.SelectedViews.get(dv)?._type_collection !== CollectionViewType.Docking);
}
export function SelectedSchemaDoc(): Doc | undefined {
return manager.SelectedSchemaDocument;
}
export function Docs(): Doc[] {
return manager.SelectedViews.map(dv => dv.rootDoc).filter(doc => doc?._type_collection !== CollectionViewType.Docking);
- // Array.from(manager.SelectedViewsMap.values()).filter(doc => doc?._type_collection !== CollectionViewType.Docking);
}
}
ScriptingGlobals.add(function SelectionManager_selectedDocType(type: string, expertMode: boolean, checkContext?: boolean) {
diff --git a/src/client/util/SettingsManager.tsx b/src/client/util/SettingsManager.tsx
index f75322905..39c471970 100644
--- a/src/client/util/SettingsManager.tsx
+++ b/src/client/util/SettingsManager.tsx
@@ -12,7 +12,9 @@ import { addStyleSheet, addStyleSheetRule, Utils } from '../../Utils';
import { GoogleAuthenticationManager } from '../apis/GoogleAuthenticationManager';
import { DocServer } from '../DocServer';
import { Networking } from '../Network';
+import { GestureOverlay } from '../views/GestureOverlay';
import { MainViewModal } from '../views/MainViewModal';
+import { FontIconBox } from '../views/nodes/FontIconBox/FontIconBox';
import { GroupManager } from './GroupManager';
import './SettingsManager.scss';
import { undoBatch } from './UndoManager';
@@ -228,8 +230,8 @@ export class SettingsManager extends React.Component<{}> {
formLabel={'Show Button Labels'}
formLabelPlacement={'right'}
toggleType={ToggleType.SWITCH}
- onClick={e => Doc.SetShowIconLabels(!Doc.GetShowIconLabels())}
- toggleStatus={Doc.GetShowIconLabels()}
+ onClick={e => (FontIconBox.ShowIconLabels = !FontIconBox.ShowIconLabels)}
+ toggleStatus={FontIconBox.ShowIconLabels}
size={Size.XSMALL}
color={SettingsManager.userColor}
/>
@@ -237,8 +239,8 @@ export class SettingsManager extends React.Component<{}> {
formLabel={'Recognize Ink Gestures'}
formLabelPlacement={'right'}
toggleType={ToggleType.SWITCH}
- onClick={e => Doc.SetRecognizeGestures(!Doc.GetRecognizeGestures())}
- toggleStatus={Doc.GetRecognizeGestures()}
+ onClick={e => (GestureOverlay.RecognizeGestures = !GestureOverlay.RecognizeGestures)}
+ toggleStatus={GestureOverlay.RecognizeGestures}
size={Size.XSMALL}
color={SettingsManager.userColor}
/>
@@ -448,7 +450,7 @@ export class SettingsManager extends React.Component<{}> {
val: freeformScrollMode.Zoom,
},
]}
- selectedVal={StrCast(Doc.UserDoc().freeformScrollMode)}
+ selectedVal={StrCast(Doc.UserDoc().freeformScrollMode, 'zoom')}
setSelectedVal={val => this.setFreeformScrollMode(val as string)}
dropdownType={DropdownType.SELECT}
type={Type.TERT}
diff --git a/src/client/util/SnappingManager.ts b/src/client/util/SnappingManager.ts
index c0cd94067..fce43eef6 100644
--- a/src/client/util/SnappingManager.ts
+++ b/src/client/util/SnappingManager.ts
@@ -3,6 +3,8 @@ import { Doc } from '../../fields/Doc';
export namespace SnappingManager {
class Manager {
+ @observable ShiftKey = false;
+ @observable CtrlKey = false;
@observable IsDragging: boolean = false;
@observable IsResizing: Doc | undefined;
@observable CanEmbed: boolean = false;
@@ -33,6 +35,12 @@ export namespace SnappingManager {
return manager.vertSnapLines;
}
+ export function SetShiftKey(down: boolean) {
+ runInAction(() => (manager.ShiftKey = down));
+ }
+ export function SetCtrlKey(down: boolean) {
+ runInAction(() => (manager.CtrlKey = down));
+ }
export function SetIsDragging(dragging: boolean) {
runInAction(() => (manager.IsDragging = dragging));
}
@@ -42,6 +50,12 @@ export namespace SnappingManager {
export function SetCanEmbed(canEmbed: boolean) {
runInAction(() => (manager.CanEmbed = canEmbed));
}
+ export function GetShiftKey() {
+ return manager.ShiftKey;
+ }
+ export function GetCtrlKey() {
+ return manager.CtrlKey;
+ }
export function GetIsDragging() {
return manager.IsDragging;
}
diff --git a/src/client/util/Transform.ts b/src/client/util/Transform.ts
index e9170ec36..dca37c960 100644
--- a/src/client/util/Transform.ts
+++ b/src/client/util/Transform.ts
@@ -2,65 +2,105 @@ export class Transform {
private _translateX: number = 0;
private _translateY: number = 0;
private _scale: number = 1;
+ private _rotate: number = 0;
static Identity(): Transform {
return new Transform(0, 0, 1);
}
- get TranslateX(): number { return this._translateX; }
- get TranslateY(): number { return this._translateY; }
- get Scale(): number { return this._scale; }
+ get TranslateX(): number {
+ return this._translateX;
+ }
+ get TranslateY(): number {
+ return this._translateY;
+ }
+ get Scale(): number {
+ return this._scale;
+ }
+ get Rotate(): number {
+ return this._rotate;
+ }
+ get RotateDeg(): number {
+ return (this._rotate * 180) / Math.PI;
+ }
- constructor(x: number, y: number, scale: number) {
+ /**
+ * Represents a transformation/scale matrix (can contain a rotation value, but it is not used when transforming points)
+ * @param x
+ * @param y
+ * @param scale
+ * @param rotation NOTE: this is passed along but is NOT used by any of the transformation functionsStores
+ */
+ constructor(x: number, y: number, scale: number, rotationRadians?: number) {
this._translateX = x;
this._translateY = y;
this._scale = scale;
+ this._rotate = rotationRadians ?? 0;
}
+ /**
+ * Rotate in radians
+ * @param rot
+ * @returns the modified transformation
+ */
+ rotate = (rot: number): this => {
+ this._rotate += rot;
+ return this;
+ };
+ /**
+ * Rotation in degrees
+ * @param rot
+ * @returns the modified transformation
+ */
+ rotateDeg = (rot: number): this => {
+ this._rotate += (rot * Math.PI) / 180;
+ return this;
+ };
+
translate = (x: number, y: number): this => {
this._translateX += x;
this._translateY += y;
return this;
- }
+ };
scale = (scale: number): this => {
this._scale *= scale;
this._translateX *= scale;
this._translateY *= scale;
return this;
- }
+ };
scaleAbout = (scale: number, x: number, y: number): this => {
this._translateX += x * this._scale - x * this._scale * scale;
this._translateY += y * this._scale - y * this._scale * scale;
this._scale *= scale;
return this;
- }
+ };
transform = (transform: Transform): this => {
this._translateX = transform._translateX + transform._scale * this._translateX;
this._translateY = transform._translateY + transform._scale * this._translateY;
this._scale *= transform._scale;
return this;
- }
+ };
preTranslate = (x: number, y: number): this => {
this._translateX += this._scale * x;
this._translateY += this._scale * y;
return this;
- }
+ };
preScale = (scale: number): this => {
this._scale *= scale;
return this;
- }
+ };
preTransform = (transform: Transform): this => {
this._translateX += transform._translateX * this._scale;
this._translateY += transform._translateY * this._scale;
this._scale *= transform._scale;
return this;
- }
+ };
translated = (x: number, y: number): Transform => this.copy().translate(x, y);
@@ -82,18 +122,17 @@ export class Transform {
y *= this._scale;
y += this._translateY;
return [x, y];
- }
+ };
transformDirection = (x: number, y: number): [number, number] => [x * this._scale, y * this._scale];
- transformBounds(x: number, y: number, width: number, height: number): { x: number, y: number, width: number, height: number } {
+ transformBounds(x: number, y: number, width: number, height: number): { x: number; y: number; width: number; height: number } {
[x, y] = this.transformPoint(x, y);
[width, height] = this.transformDirection(width, height);
return { x, y, width, height };
}
- inverse = () => new Transform(-this._translateX / this._scale, -this._translateY / this._scale, 1 / this._scale);
-
- copy = () => new Transform(this._translateX, this._translateY, this._scale);
+ inverse = () => new Transform(-this._translateX / this._scale, -this._translateY / this._scale, 1 / this._scale, -this._rotate);
-} \ No newline at end of file
+ copy = () => new Transform(this._translateX, this._translateY, this._scale, this._rotate);
+}