aboutsummaryrefslogtreecommitdiff
path: root/src/client/views
diff options
context:
space:
mode:
authorbobzel <zzzman@gmail.com>2023-11-17 21:53:36 -0500
committerbobzel <zzzman@gmail.com>2023-11-17 21:53:36 -0500
commit0dc39baf9630ae5aeaa41b89523ec6bf96d0b198 (patch)
tree6664d8e16c4dddfc4ed3cf88f5a65505eb4913ba /src/client/views
parent96d27379d77b77f7496a1b2c5f30824cc04370c0 (diff)
major overhaul of resizing code. updated doc fields for enabling native with modification to be cleaner. added Vcenter option for text in menu bar. fixed doc rotation. enabled scaling of DataViz views. fixed text sidebar opening size and sidebar issues with native dims for PDF/Web
Diffstat (limited to 'src/client/views')
-rw-r--r--src/client/views/DocumentDecorations.tsx312
-rw-r--r--src/client/views/InkControlPtHandles.tsx7
-rw-r--r--src/client/views/MainView.tsx1
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx2
-rw-r--r--src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx2
-rw-r--r--src/client/views/global/globalScripts.ts14
-rw-r--r--src/client/views/nodes/CollectionFreeFormDocumentView.tsx2
-rw-r--r--src/client/views/nodes/DataVizBox/DataVizBox.tsx10
-rw-r--r--src/client/views/nodes/DocumentView.tsx4
-rw-r--r--src/client/views/nodes/PDFBox.tsx2
-rw-r--r--src/client/views/nodes/WebBox.tsx13
-rw-r--r--src/client/views/nodes/formattedText/FormattedTextBox.tsx6
12 files changed, 167 insertions, 208 deletions
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 33886e791..8df5740fa 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -2,18 +2,17 @@ import { IconProp } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { Tooltip } from '@material-ui/core';
import { IconButton } from 'browndash-components';
-import { action, computed, observable, reaction } from 'mobx';
+import { action, computed, observable, reaction, runInAction } from 'mobx';
import { observer } from 'mobx-react';
import { FaUndo } from 'react-icons/fa';
-import { DateField } from '../../fields/DateField';
import { Doc, DocListCast, Field, HierarchyMapping, ReverseHierarchyMap } from '../../fields/Doc';
import { AclAdmin, AclAugment, AclEdit, DocData } from '../../fields/DocSymbols';
import { InkField } from '../../fields/InkField';
import { RichTextField } from '../../fields/RichTextField';
import { ScriptField } from '../../fields/ScriptField';
-import { Cast, DocCast, NumCast, StrCast } from '../../fields/Types';
+import { BoolCast, Cast, DocCast, NumCast, StrCast } from '../../fields/Types';
import { GetEffectiveAcl } from '../../fields/util';
-import { aggregateBounds, emptyFunction, numberValue, returnFalse, setupMoveUpEvents, Utils } from '../../Utils';
+import { emptyFunction, numberValue, returnFalse, setupMoveUpEvents, Utils } from '../../Utils';
import { Docs } from '../documents/Documents';
import { DocumentType } from '../documents/DocumentTypes';
import { DocumentManager } from '../util/DocumentManager';
@@ -36,6 +35,7 @@ import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
import { ImageBox } from './nodes/ImageBox';
import React = require('react');
import _ = require('lodash');
+import { DateField } from '../../fields/DateField';
@observer
export class DocumentDecorations extends React.Component<{ PanelWidth: number; PanelHeight: number; boundsLeft: number; boundsTop: number }, { value: string }> {
@@ -46,11 +46,8 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
private _linkBoxHeight = 20 + 3; // link button height + margin
private _titleHeight = 20;
private _resizeUndo?: UndoManager.Batch;
- private _offX = 0;
- private _offY = 0; // offset from click pt to inner edge of resize border
- private _snapX = 0;
- private _snapY = 0; // last snapped location of resize border
- private _dragHeights = new Map<Doc, { start: number; lowest: number }>();
+ private _offset = { x: 0, y: 0 }; // offset from click pt to inner edge of resize border
+ private _snapPt = { x: 0, y: 0 }; // last snapped location of resize border
private _inkDragDocs: { doc: Doc; x: number; y: number; width: number; height: number }[] = [];
@observable private _accumulatedTitle = '';
@@ -479,29 +476,24 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
DocumentView.Interacting = true; // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them
this._resizeHdlId = e.currentTarget.className;
const bounds = e.currentTarget.getBoundingClientRect();
- this._offX = this._resizeHdlId.toLowerCase().includes('left') ? bounds.right - e.clientX : bounds.left - e.clientX;
- this._offY = this._resizeHdlId.toLowerCase().includes('top') ? bounds.bottom - e.clientY : bounds.top - e.clientY;
+ this._offset = { x: this._resizeHdlId.toLowerCase().includes('left') ? bounds.right - e.clientX : bounds.left - e.clientX, y: this._resizeHdlId.toLowerCase().includes('top') ? bounds.bottom - e.clientY : bounds.top - e.clientY };
this._resizeUndo = UndoManager.StartBatch('drag resizing');
- this._snapX = e.pageX;
- this._snapY = e.pageY;
- const ffviewSet = new Set<CollectionFreeFormView>();
- SelectionManager.Views().forEach(docView => {
- docView.CollectionFreeFormView && ffviewSet.add(docView.CollectionFreeFormView);
- this._dragHeights.set(docView.layoutDoc, { start: NumCast(docView.rootDoc._height), lowest: NumCast(docView.rootDoc._height) });
- });
- Array.from(ffviewSet).map(ffview => ffview.dragStarting(false, false));
+ this._snapPt = { x: e.pageX, y: e.pageY };
+ SelectionManager.Views().forEach(docView => docView.CollectionFreeFormView?.dragStarting(false, false));
};
+ _lock: any;
onPointerMove = (e: PointerEvent, down: number[], move: number[]): boolean => {
const first = SelectionManager.Views()[0];
const effectiveAcl = GetEffectiveAcl(first.rootDoc);
if (!(effectiveAcl == AclAdmin || effectiveAcl == AclEdit || effectiveAcl == AclAugment)) return false;
if (!first) return false;
- let thisPt = { x: e.clientX - this._offX, y: e.clientY - this._offY };
+ let thisPt = { x: e.clientX - this._offset.x, y: e.clientY - this._offset.y };
var fixedAspect = Doc.NativeAspect(first.layoutDoc);
+ const dragHdl = this._resizeHdlId.split(' ')[0].replace('documentDecorations-', '').replace('Resizer', '');
- const resizeHdl = this._resizeHdlId.split(' ')[0];
- if (fixedAspect && (resizeHdl === 'documentDecorations-bottomRightResizer' || resizeHdl === 'documentDecorations-topLeftResizer')) {
+ // do snapping of drag point
+ if (fixedAspect && (dragHdl === 'bottomRight' || dragHdl === 'topLeft')) {
// need to generalize for bl and tr drag handles
const project = (p: number[], a: number[], b: number[]) => {
const atob = [b[0] - a[0], b[1] - a[1]];
@@ -513,173 +505,124 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
return [a[0] + atob[0] * t, a[1] + atob[1] * t];
};
const tl = first.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
- const drag = project([e.clientX + this._offX, e.clientY + this._offY], tl, [tl[0] + fixedAspect, tl[1] + 1]);
+ const drag = project([e.clientX + this._offset.x, e.clientY + this._offset.y], tl, [tl[0] + fixedAspect, tl[1] + 1]);
thisPt = DragManager.snapDragAspect(drag, fixedAspect);
} else {
- thisPt = DragManager.snapDrag(e, -this._offX, -this._offY, this._offX, this._offY);
+ thisPt = DragManager.snapDrag(e, -this._offset.x, -this._offset.y, this._offset.x, this._offset.y);
}
- move[0] = thisPt.x - this._snapX;
- move[1] = thisPt.y - this._snapY;
- this._snapX = thisPt.x;
- this._snapY = thisPt.y;
- let dragBottom = false,
- dragRight = false,
- dragBotRight = false,
- dragTop = false;
- let dXin = 0,
- dYin = 0,
- dWin = 0,
- dHin = 0;
- switch (this._resizeHdlId.split(' ')[0]) {
- case '':
- break;
- case 'documentDecorations-topLeftResizer':
- dXin = -1;
- dYin = -1;
- dWin = -move[0];
- dHin = -move[1];
- break;
- case 'documentDecorations-topRightResizer':
- dWin = move[0];
- dYin = -1;
- dHin = -move[1];
- break;
- case 'documentDecorations-topResizer':
- dYin = -1;
- dHin = -move[1];
- dragTop = true;
- break;
- case 'documentDecorations-bottomLeftResizer':
- dXin = -1;
- dWin = -move[0];
- dHin = move[1];
- break;
- case 'documentDecorations-bottomRightResizer':
- dWin = move[0];
- dHin = move[1];
- dragBotRight = true;
- break;
- case 'documentDecorations-bottomResizer':
- dHin = move[1];
- dragBottom = true;
- break;
- case 'documentDecorations-leftResizer':
- dXin = -1;
- dWin = -move[0];
- break;
- case 'documentDecorations-rightResizer':
- dWin = move[0];
- dragRight = true;
- break;
- }
+ const { scale, refPt } = this.getResizeVals(thisPt, dragHdl);
+ // resize selected docs
+ !this._lock && runInAction(async () => {
+ this._lock = true;
+ this._snapPt = thisPt;
+ e.ctrlKey && (SelectionManager.Views().forEach(docView => !Doc.NativeHeight(docView.props.Document) && docView.toggleNativeDimensions()));
+ const fixedAspect = SelectionManager.Docs().some(this.hasFixedAspect);
+ SelectionManager.Views().forEach(docView =>
+ this.resizeView(docView, refPt, scale.x === 1 && fixedAspect ? scale.y : scale.x,
+ scale.x !== 1 && fixedAspect ? scale.x : scale.y, { dragHdl, ctrlKey:e.ctrlKey })); // prettier-ignore
+ await new Promise<any>(res => setTimeout(() => res(this._lock = undefined)));
+ }); // prettier-ignore
- const isGroup = first.rootDoc._isGroup ? first.rootDoc : undefined;
- const scaleViews = isGroup ? DocListCast(isGroup.data).map(doc => DocumentManager.Instance.getFirstDocumentView(doc)!) : SelectionManager.Views();
- const aggBounds = aggregateBounds(scaleViews.map(view => view.rootDoc) as any, 0, 0);
- const refWidth = aggBounds.r - aggBounds.x;
- const refHeight = aggBounds.b - aggBounds.y;
- const scaleRefPt = first.props
- .ScreenToLocalTransform()
- .inverse()
- .transformPoint(
- NumCast(isGroup?._xPadding) + (dXin ? refWidth : 0), //
- NumCast(isGroup?._yPadding) + (dYin ? refHeight : 0)
- );
- scaleViews.forEach(
- action((docView: DocumentView) => {
- if (e.ctrlKey && !Doc.NativeHeight(docView.props.Document)) docView.toggleNativeDimensions();
- if (dXin !== 0 || dYin !== 0 || dWin !== 0 || dHin !== 0) {
- const doc = docView.rootDoc;
- const refCent = docView.props.ScreenToLocalTransform().transformPoint(scaleRefPt[0], scaleRefPt[1]);
-
- if (doc.nativeHeightUnfrozen && !NumCast(doc.nativeHeight) && doc._nativeWidth !== undefined) {
- doc._nativeHeight = (NumCast(doc._height) / NumCast(doc._width, 1)) * docView.nativeWidth;
- }
- const nwidth = docView.nativeWidth;
- const nheight = docView.nativeHeight;
- const docwidth = NumCast(doc._width);
- let docheight = (hgt => (!hgt || isNaN(hgt) ? 20 : hgt))(NumCast(doc._height) || (nheight / nwidth) * docwidth);
- let dW = docwidth * (dWin / refWidth);
- let dH = docheight * (dHin / refHeight);
- const scale = docView.props.ScreenToLocalTransform().Scale;
- const modifyNativeDim = (e.ctrlKey && doc.nativeDimModifiable) || (doc.layout_forceReflow && !dragBottom && !dragTop) || (doc.nativeHeightUnfrozen && (dragBottom || dragTop || e.ctrlKey));
- if (nwidth && nheight) {
- if (nwidth / nheight !== docwidth / docheight && !dragBottom && !dragTop) {
- docheight = (nheight / nwidth) * docwidth;
- }
- if (modifyNativeDim && !dragBottom && !dragTop) {
- // ctrl key enables modification of the nativeWidth or nativeHeight durin the interaction
- if (Math.abs(dW) > Math.abs(dH)) dH = (dW * nheight) / nwidth;
- else dW = (dH * nwidth) / nheight;
- }
- }
- let actualdW = Math.max(docwidth + dW * scale, 20);
- let actualdH = Math.max(docheight + dH * scale, 20);
- let dX = !dWin ? 0 : (scale * refCent[0] * -dWin) / refWidth;
- let dY = !dHin ? 0 : (scale * refCent[1] * -dHin) / refHeight;
- const preserveNativeDim = !doc._nativeHeightUnfrozen && !doc._nativeDimModifiable;
- const fixedAspect = nwidth && nheight && (!doc._layout_fitWidth || preserveNativeDim || e.ctrlKey || doc.nativeHeightUnfrozen || doc.nativeDimModifiable);
- if (fixedAspect) {
- if ((Math.abs(dW) > Math.abs(dH) && ((!dragBottom && !dragTop) || !modifyNativeDim)) || dragRight) {
- if (dragRight && modifyNativeDim) {
- if (Doc.NativeWidth(doc)) {
- doc._nativeWidth = (actualdW / (docwidth || 1)) * Doc.NativeWidth(doc);
- }
- } else {
- if (!doc._layout_fitWidth || preserveNativeDim) {
- actualdH = (nheight / nwidth) * actualdW;
- dYin && (dY = -dW * scale * (nheight / nwidth));
- doc._height = actualdH;
- } else if (!modifyNativeDim || dragBotRight) {
- doc._height = actualdH;
- }
- }
- doc._width = actualdW;
- } else {
- if ((dragBottom || dragTop) && (modifyNativeDim || (docView.layoutDoc.nativeHeightUnfrozen && docView.layoutDoc._layout_fitWidth))) {
- // frozen web pages, PDFs, and some RTFS have frozen nativewidth/height. But they are marked to allow their nativeHeight
- // to be explicitly modified with fitWidth and vertical resizing. (ie, with fitWidth they can't grow horizontally to match
- // a vertical resize so it makes more sense to change their nativeheight even if the ctrl key isn't used)
- doc._nativeHeight = (actualdH / (docheight || 1)) * Doc.NativeHeight(doc);
- doc._layout_autoHeight = false;
- } else {
- if (!doc._layout_fitWidth || preserveNativeDim) {
- actualdW = (nwidth / nheight) * actualdH;
- dXin && (dX = -dH * scale * (nwidth / nheight));
- doc._width = actualdW;
- } else if (!modifyNativeDim || dragBotRight) {
- doc._width = actualdW;
- }
- }
- if (!modifyNativeDim) {
- actualdH = (nheight / nwidth) * NumCast(doc._width); //, actualdH);
- }
- doc._height = actualdH;
- }
- } else {
- const rotCtr = [docwidth / 2, docheight / 2];
- const tlRotated = Utils.rotPt(-rotCtr[0], -rotCtr[1], (NumCast(doc._rotation) / 180) * Math.PI);
-
- const maxHeight = doc.nativeHeightUnfrozen || !nheight ? 0 : Math.max(nheight, NumCast(doc.scrollHeight, NumCast(doc[docView.LayoutFieldKey + '_scrollHeight']))) * docView.NativeDimScaling();
- dH && (doc._height = actualdH > maxHeight && maxHeight ? maxHeight : actualdH);
- dW && (doc._width = actualdW);
- dH && (doc._layout_autoHeight = false);
-
- const rotCtr2 = [NumCast(doc._width) / 2, NumCast(doc._height) / 2];
- const tlRotated2 = Utils.rotPt(-rotCtr2[0], -rotCtr2[1], (NumCast(doc._rotation) / 180) * Math.PI);
- doc.x = NumCast(doc.x) + tlRotated.x + rotCtr[0] - (tlRotated2.x + rotCtr2[0]); // doc shifts by amount topleft moves because rotation is about center of doc
- doc.y = NumCast(doc.y) + tlRotated.y + rotCtr[1] - (tlRotated2.y + rotCtr2[1]);
- }
- doc.x = NumCast(doc.x) + dX;
- doc.y = NumCast(doc.y) + dY;
- doc._layout_modificationDate = new DateField();
+ return false;
+ };
+
+ //
+ // determines how much to resize, and determines the resize reference point
+ //
+ getResizeVals = (thisPt: { x: number; y: number }, dragHdl: string) => {
+ const [w, h] = [this.Bounds.r - this.Bounds.x, this.Bounds.b - this.Bounds.y];
+ const [moveX, moveY] = [thisPt.x - this._snapPt.x, thisPt.y - this._snapPt.y];
+ switch (dragHdl) {
+ case 'topLeft': return { scale: { x: 1 - moveX / w, y: 1 -moveY / h }, refPt: [this.Bounds.r, this.Bounds.b] };
+ case 'topRight': return { scale: { x: 1 + moveX / w, y: 1 -moveY / h }, refPt: [this.Bounds.x, this.Bounds.b] };
+ case 'top': return { scale: { x: 1, y: 1 -moveY / h }, refPt: [this.Bounds.x, this.Bounds.b] };
+ case 'left': return { scale: { x: 1 - moveX / w, y: 1 }, refPt: [this.Bounds.r, this.Bounds.y] };
+ case 'bottomLeft': return { scale: { x: 1 - moveX / w, y: 1 + moveY / h }, refPt: [this.Bounds.r, this.Bounds.y] };
+ case 'right': return { scale: { x: 1 + moveX / w, y: 1 }, refPt: [this.Bounds.x, this.Bounds.y] };
+ case 'bottomRight':return { scale: { x: 1 + moveX / w, y: 1 + moveY / h }, refPt: [this.Bounds.x, this.Bounds.y] };
+ case 'bottom': return { scale: { x: 1, y: 1 + moveY / h }, refPt: [this.Bounds.x, this.Bounds.y] };
+ default: return { scale: { x: 1, y: 1 }, refPt: [this.Bounds.x, this.Bounds.y] };
+ } // prettier-ignore
+ };
+
+ //
+ // determines if anything being dragged directly or via a group has a fixed aspect ratio (in which case we resize uniformly)
+ //
+ hasFixedAspect = (doc: Doc): boolean => (doc.isGroup ? DocListCast(doc.data).some(this.hasFixedAspect) : !BoolCast(doc.layout_nativeDimEditable));
+
+ //
+ // resize a single DocumentView about the specified reference point, possibly setting/updating the native dimensions of the Doc
+ //
+ resizeView = (docView: DocumentView, refPt: number[], scaleX: number, scaleY: number, opts: { dragHdl: string; ctrlKey: boolean }) => {
+ const doc = docView.rootDoc;
+ if (doc.isGroup) {
+ DocListCast(doc.data)
+ .map(member => DocumentManager.Instance.getDocumentView(member, docView)!)
+ .forEach(member => this.resizeView(member, refPt, scaleX, scaleY, opts));
+ doc.xPadding = NumCast(doc.xPadding) * scaleX;
+ doc.yPadding = NumCast(doc.yPadding) * scaleY;
+ } else {
+ const doc = docView.rootDoc;
+ const refCent = docView.props.ScreenToLocalTransform().transformPoint(refPt[0], refPt[1]); // fixed reference point for resize (ie, a point that doesn't move)
+ const [nwidth, nheight] = [docView.nativeWidth, docView.nativeHeight];
+ const [initWidth, initHeight] = [NumCast(doc._width, 1), NumCast(doc._height)];
+
+ const modifyNativeDim =
+ (opts.ctrlKey && doc.layout_nativeDimEditable) || // e.g., PDF or web page
+ (doc.layout_reflowHorizontal && opts.dragHdl !== 'bottom' && opts.dragHdl !== 'top') || // eg rtf or some web pages
+ (doc.layout_reflowVertical && (opts.dragHdl === 'bottom' || opts.dragHdl === 'top' || opts.ctrlKey)); // eg rtf, web, pdf
+ if (nwidth && nheight && !modifyNativeDim) {
+ // eg., dragging right resizer on PDF -- enforce native dimensions because not expliclty overridden with ctrl or bottom resize drag
+ scaleX === 1 ? (scaleX = scaleY) : (scaleY = scaleX);
+ }
+
+ if (['right', 'left'].includes(opts.dragHdl) && modifyNativeDim && Doc.NativeWidth(doc)) {
+ const setData = Doc.NativeWidth(Doc.GetProto(doc)) === doc.nativeWidth;
+ doc.nativeWidth = scaleX * Doc.NativeWidth(doc);
+ if (setData) Doc.SetNativeWidth(Doc.GetProto(doc), NumCast(doc.nativeWidth));
+ if (doc.layout_reflowVertical && !NumCast(doc.nativeHeight)) {
+ doc._nativeHeight = (initHeight / initWidth) * nwidth; // initializes the nativeHeight for a PDF
}
- const val = this._dragHeights.get(docView.layoutDoc);
- if (val) this._dragHeights.set(docView.layoutDoc, { start: val.start, lowest: Math.min(val.lowest, NumCast(docView.layoutDoc._height)) });
- })
+ }
+ if (['bottom', 'top'].includes(opts.dragHdl) && modifyNativeDim && Doc.NativeHeight(doc)) {
+ const setData = Doc.NativeHeight(Doc.GetProto(doc)) === doc.nativeHeight;
+ doc._nativeHeight = scaleY * Doc.NativeHeight(doc);
+ if (setData) Doc.SetNativeHeight(Doc.GetProto(doc), NumCast(doc._nativeHeight));
+ }
+
+ doc._width = NumCast(doc._width) * scaleX;
+ doc._height = NumCast(doc._height) * scaleY;
+ const { deltaX, deltaY } = this.realignRefPt(doc, refCent, initWidth, initHeight);
+ doc.x = NumCast(doc.x) + deltaX;
+ doc.y = NumCast(doc.y) + deltaY;
+
+ doc._layout_modificationDate = new DateField();
+ scaleY !== 1 && (doc._layout_autoHeight = undefined);
+ }
+ };
+
+ // This realigns the doc's resize reference point with where it was before resizing it.
+ // This is needed, because the transformation for doc's with a rotation is screwy:
+ // the top left of the doc is the 'origin', but the rotation happens about the center of the Doc.
+ // So resizing a rotated doc will cause it to shift -- this counteracts that shift by determine how
+ // the reference points shifted, and returning a translation to restore the reference point.
+ realignRefPt = (doc: Doc, refCent: number[], initWidth: number, initHeight: number) => {
+ const refCentPct = [refCent[0] / initWidth, refCent[1] / initHeight];
+ const rotRefStart = Utils.rotPt(
+ refCent[0] - initWidth / 2, // rotate reference pointe before scaling
+ refCent[1] - initHeight / 2,
+ (NumCast(doc._rotation) / 180) * Math.PI
);
- return false;
+ const rotRefEnd = Utils.rotPt(
+ refCentPct[0] * NumCast(doc._width) - NumCast(doc._width) / 2, // rotate reference point after scaling
+ refCentPct[1] * NumCast(doc._height) - NumCast(doc._height) / 2,
+ (NumCast(doc._rotation) / 180) * Math.PI
+ );
+ return {
+ deltaX: rotRefStart.x + initWidth / 2 - (rotRefEnd.x + NumCast(doc._width) / 2), //
+ deltaY: rotRefStart.y + initHeight / 2 - (rotRefEnd.y + NumCast(doc._height) / 2),
+ };
};
@action
@@ -691,10 +634,7 @@ export class DocumentDecorations extends React.Component<{ PanelWidth: number; P
SnappingManager.clearSnapLines();
// detect layout_autoHeight gesture and apply
- SelectionManager.Views()
- .map(docView => ({ doc: docView.layoutDoc, hgts: this._dragHeights.get(docView.layoutDoc) }))
- .filter(pair => pair.hgts && pair.hgts.lowest < pair.hgts.start && pair.hgts.lowest <= 20)
- .forEach(pair => (pair.doc._layout_autoHeight = true));
+ SelectionManager.Docs().forEach(doc => NumCast(doc._height) < 20 && (doc._layout_autoHeight = true));
//need to change points for resize, or else rotation/control points will fail.
this._inkDragDocs
.map(oldbds => ({ oldbds, inkPts: Cast(oldbds.doc.data, InkField)?.inkData || [] }))
diff --git a/src/client/views/InkControlPtHandles.tsx b/src/client/views/InkControlPtHandles.tsx
index 0d7f7ebd8..e5141b7f4 100644
--- a/src/client/views/InkControlPtHandles.tsx
+++ b/src/client/views/InkControlPtHandles.tsx
@@ -12,6 +12,7 @@ import { UndoManager } from '../util/UndoManager';
import { Colors } from './global/globalEnums';
import { InkingStroke } from './InkingStroke';
import { InkStrokeProperties } from './InkStrokeProperties';
+import { SnappingManager } from '../util/SnappingManager';
export interface InkControlProps {
inkDoc: Doc;
@@ -190,6 +191,7 @@ export class InkEndPtHandles extends React.Component<InkEndProps> {
@action
dragRotate = (e: React.PointerEvent, pt1: () => { X: number; Y: number }, pt2: () => { X: number; Y: number }) => {
+ SnappingManager.SetIsDragging(true);
setupMoveUpEvents(
this,
e,
@@ -211,6 +213,7 @@ export class InkEndPtHandles extends React.Component<InkEndProps> {
return false;
}),
action(() => {
+ SnappingManager.SetIsDragging(false);
this.props.inkView.controlUndo?.end();
this.props.inkView.controlUndo = undefined;
UndoManager.FilterBatches(['stroke', 'x', 'y', 'width', 'height']);
@@ -237,8 +240,8 @@ export class InkEndPtHandles extends React.Component<InkEndProps> {
);
return (
<svg>
- {hdl('start', this.props.startPt(), (e: React.PointerEvent) => this.dragRotate(e, this.props.startPt, this.props.endPt))}
- {hdl('end', this.props.endPt(), (e: React.PointerEvent) => this.dragRotate(e, this.props.endPt, this.props.startPt))}
+ {hdl('start', this.props.startPt(), e => this.dragRotate(e, this.props.startPt, this.props.endPt))}
+ {hdl('end', this.props.endPt(), e => this.dragRotate(e, this.props.endPt, this.props.startPt))}
</svg>
);
}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index a6f0b9e84..5bed0f923 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -252,6 +252,7 @@ export class MainView extends React.Component {
fa.faShare,
fa.faTaxi,
fa.faDownload,
+ fa.faPallet,
fa.faExpandArrowsAlt,
fa.faAmbulance,
fa.faLayerGroup,
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
index 81453c0b8..c2586fb4b 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMulticolumnView.tsx
@@ -295,7 +295,7 @@ export class CollectionMulticolumnView extends CollectionSubView() {
const aspect = Doc.NativeAspect(layout, undefined, true);
const width = () => this.lookupPixels(layout);
const height = () => PanelHeight() - 2 * NumCast(Document._yMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0);
- const docwidth = () => (layout._layout_forceReflow ? width() : Math.min(height() * aspect, width()));
+ const docwidth = () => (layout._layout_reflowHorizontal ? width() : Math.min(height() * aspect, width()));
const docheight = () => Math.min(docwidth() / aspect, height());
const dxf = () =>
this.lookupIndividualTransform(layout)
diff --git a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
index 04cfc5456..249c3551b 100644
--- a/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
+++ b/src/client/views/collections/collectionMulticolumn/CollectionMultirowView.tsx
@@ -292,7 +292,7 @@ export class CollectionMultirowView extends CollectionSubView() {
const height = () => this.lookupPixels(layout);
const width = () => PanelWidth() - 2 * NumCast(Document._xMargin) - (BoolCast(Document.showWidthLabels) ? 20 : 0);
const docheight = () => Math.min(width() / aspect, height());
- const docwidth = () => (layout._layout_forceReflow ? width() : Math.min(width(), docheight() * aspect));
+ const docwidth = () => (layout._layout_reflowHorizontal ? width() : Math.min(width(), docheight() * aspect));
const dxf = () =>
this.lookupIndividualTransform(layout)
.translate(-NumCast(Document._xMargin) - (width() - docwidth()) / 2, -NumCast(Document._yMargin) - (height() - docheight()) / 2)
diff --git a/src/client/views/global/globalScripts.ts b/src/client/views/global/globalScripts.ts
index c690b8623..3af523d73 100644
--- a/src/client/views/global/globalScripts.ts
+++ b/src/client/views/global/globalScripts.ts
@@ -181,16 +181,22 @@ ScriptingGlobals.add(function setFontAttr(attr: 'font' | 'fontColor' | 'highligh
map.get(attr)?.setDoc?.();
});
-type attrname = 'noAutoLink' | 'dictation' | 'bold' | 'italics' | 'underline' | 'left' | 'center' | 'right' | 'bullet' | 'decimal';
+type attrname = 'noAutoLink' | 'dictation' | 'bold' | 'italics' | 'underline' | 'left' | 'center' | 'right' | 'vcent' | 'bullet' | 'decimal';
type attrfuncs = [attrname, { checkResult: () => boolean; toggle: () => any }];
ScriptingGlobals.add(function toggleCharStyle(charStyle: attrname, checkResult?: boolean) {
const textView = RichTextMenu.Instance?.TextView;
const editorView = textView?.EditorView;
// prettier-ignore
- const alignments:attrfuncs[] = (['left','right','center'] as ("left"|"center"|"right")[]).map((where) =>
- [ where, { checkResult: () =>(editorView ? (RichTextMenu.Instance.textAlign ===where): (Doc.UserDoc().textAlign ===where) ? true:false),
- toggle: () => (editorView?.state ? RichTextMenu.Instance.align(editorView, editorView.dispatch, where):(Doc.UserDoc().textAlign = where))}]);
+ const alignments:attrfuncs[] = (['left','right','center','vcent'] as ("left"|"center"|"right"|"vcent")[]).map((where) =>
+ [ where, { checkResult: () =>(editorView ? (where === 'vcent' ? SelectionManager.Docs().some(doc => doc.layout_centered):
+ (RichTextMenu.Instance.textAlign === where)):
+ where === 'vcent' ? BoolCast(Doc.UserDoc().layout_centered):
+ (Doc.UserDoc().textAlign ===where) ? true:false),
+ toggle: () => (editorView?.state ? (where === 'vcent' ? SelectionManager.Docs().forEach(doc => doc.layout_centered = !doc.layout_centered):
+ RichTextMenu.Instance.align(editorView, editorView.dispatch, where)):
+ where === 'vcent' ? Doc.UserDoc().layout_centered = !Doc.UserDoc().layout_centered:
+ (Doc.UserDoc().textAlign = where))}]); // prettier-ignore
// prettier-ignore
const listings:attrfuncs[] = (['bullet','decimal'] as attrname[]).map(list =>
[ list, { checkResult: () => (editorView ? RichTextMenu.Instance.getActiveListStyle() === list:false),
diff --git a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
index a05d6c904..582a5518a 100644
--- a/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
+++ b/src/client/views/nodes/CollectionFreeFormDocumentView.tsx
@@ -62,7 +62,7 @@ export class CollectionFreeFormDocumentViewWrapper extends DocComponent<Collecti
w_Y = () => this.Y; // prettier-ignore
w_Z = () => this.Z; // prettier-ignore
w_ZIndex = () => this.ZIndex ?? NumCast(this.props.Document.zIndex); // prettier-ignore
- w_Rot = () => this.Rotation ?? NumCast(this.props.Document._rotation); // prettier-ignore
+ w_Rotation = () => this.Rotation ?? NumCast(this.props.Document._rotation); // prettier-ignore
w_Opacity = () => this.Opacity; // prettier-ignore
w_BackgroundColor = () => this.BackgroundColor ?? Cast(this.props.Document._backgroundColor, 'string', null); // prettier-ignore
w_Color = () => this.Color ?? Cast(this.props.Document._color, 'string', null); // prettier-ignore
diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
index 299494c83..b3f813eda 100644
--- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx
+++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx
@@ -115,8 +115,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
layoutDoc: this.layoutDoc,
records: this.records,
axes: this.axes,
- height: (this.props.PanelHeight() - 32) /* height of 'change view' button */ * 0.9,
- width: this.props.PanelWidth() * 0.9,
+ height: (this.props.PanelHeight() * (this.props.NativeDimScaling?.() || 1) - 32) /* height of 'change view' button */ * 0.9,
+ width: this.props.PanelWidth() * (this.props.NativeDimScaling?.() || 1) * 0.9,
margin: { top: 10, right: 25, bottom: 75, left: 45 },
};
if (!this.records.length) return 'no data/visualization';
@@ -133,6 +133,8 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
};
render() {
+ const scale = this.props.NativeDimScaling?.() || 1;
+
return !this.records.length ? (
// displays how to get data into the DataVizBox if its empty
<div className="start-message">To create a DataViz box, either import / drag a CSV file into your canvas or copy a data table and use the command 'ctrl + p' to bring the data table to your canvas.</div>
@@ -141,6 +143,10 @@ export class DataVizBox extends ViewBoxAnnotatableComponent<FieldViewProps>() {
className="dataViz"
style={{
pointerEvents: this.props.isContentActive() === true ? 'all' : 'none',
+ width: `${100 / scale}%`,
+ height: `${100 / scale}%`,
+ transform: `scale(${scale})`,
+ position: 'absolute',
}}
onWheel={e => e.stopPropagation()}
ref={r =>
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index d1caf0acf..e3d6c3fdf 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -1495,7 +1495,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
return this.effectiveNativeWidth ? this.effectiveNativeWidth * this.nativeScaling : this.props.PanelWidth();
}
@computed get panelHeight() {
- if (this.effectiveNativeHeight && (!this.layout_fitWidth || !this.layoutDoc.nativeHeightUnfrozen)) {
+ if (this.effectiveNativeHeight && (!this.layout_fitWidth || !this.layoutDoc.layout_reflowVertical)) {
return Math.min(this.props.PanelHeight(), this.effectiveNativeHeight * this.nativeScaling);
}
return this.props.PanelHeight();
@@ -1507,7 +1507,7 @@ export class DocumentView extends React.Component<DocumentViewProps> {
return this.effectiveNativeWidth &&
this.effectiveNativeHeight &&
Math.abs(this.Xshift) < 0.001 &&
- (!this.layoutDoc.nativeHeightUnfrozen || (!this.layout_fitWidth && this.effectiveNativeHeight * this.nativeScaling <= this.props.PanelHeight()))
+ (!this.layoutDoc.layout_reflowVertical || (!this.layout_fitWidth && this.effectiveNativeHeight * this.nativeScaling <= this.props.PanelHeight()))
? Math.max(0, (this.props.PanelHeight() - this.effectiveNativeHeight * this.nativeScaling) / 2)
: 0;
}
diff --git a/src/client/views/nodes/PDFBox.tsx b/src/client/views/nodes/PDFBox.tsx
index bde1d5fa4..185c6553a 100644
--- a/src/client/views/nodes/PDFBox.tsx
+++ b/src/client/views/nodes/PDFBox.tsx
@@ -347,7 +347,7 @@ export class PDFBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
toggleSidebar = action((preview: boolean = false) => {
const nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']);
const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth;
- const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth + PDFBox.sidebarResizerWidth : 0) + nativeWidth) / nativeWidth;
+ const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? PDFBox.openSidebarWidth + PDFBox.sidebarResizerWidth : 0) + NumCast(this.layoutDoc._width)) / NumCast(this.layoutDoc._width);
const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth);
if (preview) {
this._previewNativeWidth = nativeWidth * sideratio;
diff --git a/src/client/views/nodes/WebBox.tsx b/src/client/views/nodes/WebBox.tsx
index a452b1cdd..d9ea48c3b 100644
--- a/src/client/views/nodes/WebBox.tsx
+++ b/src/client/views/nodes/WebBox.tsx
@@ -707,10 +707,10 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
icon: 'snowflake',
});
funcs.push({
- description: (!this.layoutDoc.layout_forceReflow ? 'Force' : 'Prevent') + ' Reflow',
+ description: (!this.layoutDoc.layout_reflowHorizontal ? 'Force' : 'Prevent') + ' Reflow',
event: () => {
- const nw = !this.layoutDoc.layout_forceReflow ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.NativeDimScaling?.() || 1);
- this.layoutDoc.layout_forceReflow = !nw;
+ const nw = !this.layoutDoc.layout_reflowHorizontal ? undefined : Doc.NativeWidth(this.layoutDoc) - this.sidebarWidth() / (this.props.NativeDimScaling?.() || 1);
+ this.layoutDoc.layout_reflowHorizontal = !nw;
if (nw) {
Doc.SetInPlace(this.layoutDoc, this.fieldKey + '_nativeWidth', nw, true);
}
@@ -872,13 +872,13 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
toggleSidebar = action((preview: boolean = false) => {
var nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']);
if (!nativeWidth) {
- const defaultNativeWidth = this.rootDoc[this.fieldKey] instanceof WebField ? 850 : NumCast(this.Document._width);
+ const defaultNativeWidth = NumCast(this.rootDoc.nativeWidth, this.rootDoc[this.fieldKey] instanceof WebField ? 850 : NumCast(this.Document._width));
Doc.SetNativeWidth(this.dataDoc, Doc.NativeWidth(this.dataDoc) || defaultNativeWidth);
Doc.SetNativeHeight(this.dataDoc, Doc.NativeHeight(this.dataDoc) || (NumCast(this.Document._height) / NumCast(this.Document._width)) * defaultNativeWidth);
nativeWidth = NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']);
}
const sideratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth : 0) + nativeWidth) / nativeWidth;
- const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth + WebBox.sidebarResizerWidth : 0) + nativeWidth) / nativeWidth;
+ const pdfratio = ((!this.layoutDoc.nativeWidth || this.layoutDoc.nativeWidth === nativeWidth ? WebBox.openSidebarWidth + WebBox.sidebarResizerWidth : 0) + NumCast(this.layoutDoc.width)) / NumCast(this.layoutDoc.width);
const curNativeWidth = NumCast(this.layoutDoc.nativeWidth, nativeWidth);
if (preview) {
this._previewNativeWidth = nativeWidth * sideratio;
@@ -890,6 +890,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
if (!this.layoutDoc._layout_showSidebar && !(this.dataDoc[this.fieldKey] instanceof WebField)) {
this.layoutDoc.nativeWidth = this.dataDoc[this.fieldKey + '_nativeWidth'] = undefined;
} else {
+ !this.layoutDoc._layout_showSidebar && (this.dataDoc[this.fieldKey + '_nativeWidth'] = this.dataDoc[this.fieldKey + '_nativeHeight'] = undefined);
this.layoutDoc.nativeWidth = nativeWidth * pdfratio;
}
}
@@ -917,7 +918,7 @@ export class WebBox extends ViewBoxAnnotatableComponent<ViewBoxAnnotatableProps
className={'webBox-cont' + (interactive ? '-interactive' : '')}
onKeyDown={e => e.stopPropagation()}
style={{
- width: !this.layoutDoc.layout_forceReflow ? NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']) || `100%` : '100%',
+ width: !this.layoutDoc.layout_reflowHorizontal ? NumCast(this.layoutDoc[this.fieldKey + '_nativeWidth']) || `100%` : '100%',
transform: `scale(${this.zoomScaling()}) translate(${-NumCast(this.layoutDoc.freeform_panX)}px, ${-NumCast(this.layoutDoc.freeform_panY)}px)`,
}}>
{this._hackHide ? null : this.urlContent}
diff --git a/src/client/views/nodes/formattedText/FormattedTextBox.tsx b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
index 9ab3189a6..a80c1e030 100644
--- a/src/client/views/nodes/formattedText/FormattedTextBox.tsx
+++ b/src/client/views/nodes/formattedText/FormattedTextBox.tsx
@@ -704,14 +704,16 @@ export class FormattedTextBox extends ViewBoxAnnotatableComponent<FieldViewProps
@action
toggleSidebar = (preview: boolean = false) => {
+ const defaultSidebar = 250;
const prevWidth = 1 - this.sidebarWidth() / Number(getComputedStyle(this._ref.current!).width.replace('px', ''));
if (preview) this._showSidebar = true;
else {
this.layoutDoc[this.SidebarKey + '_freeform_scale_max'] = 1;
- this.layoutDoc._layout_showSidebar = (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? '50%' : '0%') !== '0%';
+ this.layoutDoc._layout_showSidebar =
+ (this.layoutDoc._layout_sidebarWidthPercent = StrCast(this.layoutDoc._layout_sidebarWidthPercent, '0%') === '0%' ? `${(defaultSidebar / (NumCast(this.layoutDoc._width) + defaultSidebar)) * 100}%` : '0%') !== '0%';
}
- this.layoutDoc._width = !preview && this.SidebarShown ? NumCast(this.layoutDoc._width) * 2 : Math.max(20, NumCast(this.layoutDoc._width) * prevWidth);
+ this.layoutDoc._width = !preview && this.SidebarShown ? NumCast(this.layoutDoc._width) + defaultSidebar : Math.max(20, NumCast(this.layoutDoc._width) * prevWidth);
};
sidebarDown = (e: React.PointerEvent) => {
const batch = UndoManager.StartBatch('toggle sidebar');