aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/client/util/InteractionUtils.tsx8
-rw-r--r--src/client/views/ComponentDecorations.scss0
-rw-r--r--src/client/views/ComponentDecorations.tsx14
-rw-r--r--src/client/views/DocumentDecorations.scss468
-rw-r--r--src/client/views/DocumentDecorations.tsx16
-rw-r--r--src/client/views/GestureOverlay.tsx25
-rw-r--r--src/client/views/InkControls.tsx120
-rw-r--r--src/client/views/InkHandles.tsx25
-rw-r--r--src/client/views/InkStroke.scss14
-rw-r--r--src/client/views/InkingStroke.tsx133
-rw-r--r--src/client/views/MainView.tsx12
-rw-r--r--src/client/views/collections/CollectionMenu.tsx21
-rw-r--r--src/client/views/nodes/DocumentView.tsx1
-rw-r--r--src/client/views/search/SearchBox.tsx2
14 files changed, 535 insertions, 324 deletions
diff --git a/src/client/util/InteractionUtils.tsx b/src/client/util/InteractionUtils.tsx
index 8429a806a..4a8011e3c 100644
--- a/src/client/util/InteractionUtils.tsx
+++ b/src/client/util/InteractionUtils.tsx
@@ -3,6 +3,8 @@ import * as beziercurve from 'bezier-curve';
import * as fitCurve from 'fit-curve';
import "./InteractionUtils.scss";
import { Utils } from "../../Utils";
+import { CurrentUserUtils } from "./CurrentUserUtils";
+import { InkTool } from "../../fields/InkField";
export namespace InteractionUtils {
export const MOUSETYPE = "mouse";
@@ -139,7 +141,7 @@ export namespace InteractionUtils {
export function CreatePolyline(points: { X: number, Y: number }[], left: number, top: number,
color: string, width: number, strokeWidth: number, bezier: string, fill: string, arrowStart: string, arrowEnd: string,
- dash: string | undefined, scalex: number, scaley: number, shape: string, pevents: string, drawHalo: boolean, nodefs: boolean) {
+ dash: string | undefined, scalex: number, scaley: number, shape: string, pevents: string, opacity: number, nodefs: boolean) {
let pts: { X: number; Y: number; }[] = [];
if (shape) { //if any of the shape are true
pts = makePolygon(shape, points);
@@ -215,8 +217,8 @@ export namespace InteractionUtils {
pointerEvents: pevents as any,
stroke: color ?? "rgb(0, 0, 0)",
strokeWidth: strokeWidth,
- strokeLinejoin: "round",
- strokeLinecap: "round",
+ strokeLinejoin: color === "rgba(245, 230, 95, 0.75)" ? "miter" : "round",
+ strokeLinecap: color === "rgba(245, 230, 95, 0.75)" ? "square" : "round",
strokeDasharray: dashArray
}}
markerStart={`url(#${arrowStart + "Start" + defGuid})`}
diff --git a/src/client/views/ComponentDecorations.scss b/src/client/views/ComponentDecorations.scss
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/client/views/ComponentDecorations.scss
diff --git a/src/client/views/ComponentDecorations.tsx b/src/client/views/ComponentDecorations.tsx
new file mode 100644
index 000000000..66d1bd63d
--- /dev/null
+++ b/src/client/views/ComponentDecorations.tsx
@@ -0,0 +1,14 @@
+import { observer } from "mobx-react";
+import { SelectionManager } from "../util/SelectionManager";
+import './ComponentDecorations.scss';
+import React = require("react");
+
+@observer
+export class ComponentDecorations extends React.Component<{ boundsTop: number, boundsLeft: number }, { value: string }> {
+ static Instance: ComponentDecorations;
+
+ render() {
+ const seldoc = SelectionManager.Views().lastElement();
+ return seldoc?.ComponentView?.componentUI?.(this.props.boundsLeft, this.props.boundsTop) ?? (null);
+ }
+} \ No newline at end of file
diff --git a/src/client/views/DocumentDecorations.scss b/src/client/views/DocumentDecorations.scss
index d34efd01a..76b7481a0 100644
--- a/src/client/views/DocumentDecorations.scss
+++ b/src/client/views/DocumentDecorations.scss
@@ -1,14 +1,33 @@
@import "global/globalCssVariables";
-$linkGap : 3px;
+$linkGap: 3px;
.documentDecorations {
- position: absolute;
- z-index: 2000;
+ position: absolute;
+ z-index: 2000;
}
-
.documentDecorations-container {
- z-index: $docDecorations-zindex;
+ z-index: $docDecorations-zindex;
+ position: absolute;
+ top: 0;
+ left: 0;
+ display: grid;
+ grid-template-rows: 20px 8px 1fr 8px;
+ grid-template-columns: 8px 16px 1fr 8px 8px;
+ pointer-events: none;
+
+ .documentDecorations-centerCont {
+ grid-column: 3;
+ background: none;
+ }
+
+ .documentDecorations-selectorButton {
+ pointer-events: auto;
+ height: 15px;
+ width: 15px;
+ left: -20px;
+ top: 20px;
+ display: inline-block;
position: absolute;
top: 0;
left: 0;
@@ -123,62 +142,105 @@ $linkGap : 3px;
.documentDecorations-bottomRightResizer:hover {
opacity: 1;
}
+ }
- .documentDecorations-bottomRightResizer {
- grid-row: 4;
- }
+ .documentDecorations-topLeftResizer,
+ .documentDecorations-leftResizer,
+ .documentDecorations-bottomLeftResizer {
+ grid-column: 1;
+ }
- .documentDecorations-topRightResizer,
- .documentDecorations-bottomLeftResizer {
- cursor: nesw-resize;
- background: unset;
- opacity: 1;
- }
+ .documentDecorations-topResizer,
+ .documentDecorations-bottomResizer {
+ grid-column-start: 2;
+ grid-column-end: 5;
+ }
- .documentDecorations-topRightResizer {
- border-right: 2px solid;
- border-top: 2px solid;
- }
+ .documentDecorations-bottomRightResizer,
+ .documentDecorations-topRightResizer,
+ .documentDecorations-rightResizer {
+ grid-column-start: 5;
+ grid-column-end: 7;
+ }
+
+ .documentDecorations-rotation,
+ .documentDecorations-borderRadius {
+ grid-column: 5;
+ grid-row: 4;
+ border-radius: 100%;
+ background: black;
+ height: 8;
+ right: -12;
+ top: 12;
+ position: relative;
+ pointer-events: all;
+ cursor: nwse-resize;
+
+ .borderRadiusTooltip {
+ width: 10px;
+ height: 10px;
+ position: absolute;
+ }
+ }
+ .documentDecorations-rotation {
+ background: transparent;
+ right: -15;
+ }
+
+ .documentDecorations-topLeftResizer,
+ .documentDecorations-bottomRightResizer {
+ cursor: nwse-resize;
+ background: unset;
+ opacity: 1;
+ }
- .documentDecorations-bottomLeftResizer {
- border-left: 2px solid;
- border-bottom: 2px solid;
- }
+ .documentDecorations-topLeftResizer {
+ border-left: 2px solid;
+ border-top: solid 2px;
+ }
- .documentDecorations-topRightResizer:hover,
- .documentDecorations-bottomLeftResizer:hover {
- cursor: nesw-resize;
- background: black;
- opacity: 1;
- }
+ .documentDecorations-bottomRightResizer {
+ border-right: 2px solid;
+ border-bottom: solid 2px;
+ }
- .documentDecorations-topResizer,
- .documentDecorations-bottomResizer {
- cursor: ns-resize;
- }
+ .documentDecorations-topLeftResizer:hover,
+ .documentDecorations-bottomRightResizer:hover {
+ opacity: 1;
+ }
- .documentDecorations-leftResizer,
- .documentDecorations-rightResizer {
- cursor: ew-resize;
- }
+ .documentDecorations-bottomRightResizer {
+ grid-row: 4;
+ }
- .documentDecorations-contextMenu {
- width: 25px;
- height: calc(100% + 8px); // 8px for the height of the top resizer bar
- grid-column-start: 2;
- grid-column-end: 2;
- pointer-events: all;
- padding-left: 5px;
- cursor: pointer;
- }
+ .documentDecorations-topRightResizer,
+ .documentDecorations-bottomLeftResizer {
+ cursor: nesw-resize;
+ background: unset;
+ opacity: 1;
+ }
+
+ .documentDecorations-topRightResizer {
+ border-right: 2px solid;
+ border-top: 2px solid;
+ }
+
+ .documentDecorations-bottomLeftResizer {
+ border-left: 2px solid;
+ border-bottom: 2px solid;
+ }
+
+ .documentDecorations-topRightResizer:hover,
+ .documentDecorations-bottomLeftResizer:hover {
+ cursor: nesw-resize;
+ background: black;
+ opacity: 1;
+ }
- .documentDecorations-titleBackground {
- background: #ffffffcf;
- border-radius: 8px;
- width: 100%;
- height: 100%;
- position: absolute;
- }
+ .documentDecorations-topResizer,
+ .documentDecorations-bottomResizer {
+ cursor: ns-resize;
+ }
.documentDecorations-title {
opacity: 1;
@@ -202,67 +264,105 @@ $linkGap : 3px;
}
}
- .focus-visible {
- margin-left: 0px;
- }
-}
+ .documentDecorations-contextMenu {
+ width: 25px;
+ height: calc(100% + 8px); // 8px for the height of the top resizer bar
+ grid-column-start: 2;
+ grid-column-end: 2;
+ pointer-events: all;
+ padding-left: 5px;
+ cursor: pointer;
+ }
+ .documentDecorations-titleBackground {
+ background: #ffffffcf;
+ border-radius: 8px;
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ }
-.documentDecorations-iconifyButton {
+ .documentDecorations-title {
opacity: 1;
- grid-column-start: 4;
+ grid-column-start: 2;
grid-column-end: 4;
- pointer-events: all;
- right: 0;
- cursor: pointer;
+ pointer-events: auto;
+ overflow: hidden;
+ text-align: center;
+ display: flex;
+ margin-left: 5px;
+ height: 22px;
position: absolute;
- width: 20px;
+ .documentDecorations-titleSpan {
+ width: 100%;
+ border-radius: 8px;
+ background: #ffffffcf;
+ position: absolute;
+ display: inline-block;
+ cursor: move;
+ }
+ }
+
+ .focus-visible {
+ margin-left: 0px;
+ }
+}
+
+.documentDecorations-iconifyButton {
+ opacity: 1;
+ grid-column-start: 4;
+ grid-column-end: 4;
+ pointer-events: all;
+ right: 0;
+ cursor: pointer;
+ position: absolute;
+ width: 20px;
}
.documentDecorations-openButton {
- display: flex;
- align-items: center;
- opacity: 1;
- grid-column-start: 5;
- grid-column-end: 5;
- pointer-events: all;
- cursor: pointer;
+ display: flex;
+ align-items: center;
+ opacity: 1;
+ grid-column-start: 5;
+ grid-column-end: 5;
+ pointer-events: all;
+ cursor: pointer;
}
.documentDecorations-closeButton {
- display: flex;
- align-items: center;
- opacity: 1;
- grid-column-start: 1;
- grid-column-end: 3;
- pointer-events: all;
- cursor: pointer;
-
- >svg {
- margin: 0;
- }
+ display: flex;
+ align-items: center;
+ opacity: 1;
+ grid-column-start: 1;
+ grid-column-end: 3;
+ pointer-events: all;
+ cursor: pointer;
+
+ > svg {
+ margin: 0;
+ }
}
.documentDecorations-background {
- background: lightblue;
- position: absolute;
- opacity: 0.1;
+ background: lightblue;
+ position: absolute;
+ opacity: 0.1;
}
.linkFlyout {
- grid-column: 2/4;
+ grid-column: 2/4;
}
.linkButton-empty:hover {
- background: $medium-gray;
- transform: scale(1.05);
- cursor: pointer;
+ background: $medium-gray;
+ transform: scale(1.05);
+ cursor: pointer;
}
.linkButton-nonempty:hover {
- background: $medium-gray;
- transform: scale(1.05);
- cursor: pointer;
+ background: $medium-gray;
+ transform: scale(1.05);
+ cursor: pointer;
}
.link-button-container {
@@ -280,136 +380,136 @@ $linkGap : 3px;
}
.linkButtonWrapper {
- pointer-events: auto;
- padding-right: 5px;
- width: 25px;
+ pointer-events: auto;
+ padding-right: 5px;
+ width: 25px;
}
.linkButton-linker {
- height: 20px;
- width: 20px;
- text-align: center;
- border-radius: 50%;
- pointer-events: auto;
- color: $dark-gray;
- border: $dark-gray 1px solid;
+ height: 20px;
+ width: 20px;
+ text-align: center;
+ border-radius: 50%;
+ pointer-events: auto;
+ color: $dark-gray;
+ border: $dark-gray 1px solid;
}
.linkButton-linker:hover {
- cursor: pointer;
- transform: scale(1.05);
+ cursor: pointer;
+ transform: scale(1.05);
}
.linkButton-empty,
.linkButton-nonempty {
- height: 20px;
- width: 20px;
- border-radius: 50%;
- opacity: 0.9;
- pointer-events: auto;
- background-color: $dark-gray;
- color: $white;
- text-transform: uppercase;
- letter-spacing: 2px;
- font-size: 75%;
- transition: transform 0.2s;
- text-align: center;
- display: flex;
- justify-content: center;
- align-items: center;
-
- &:hover {
- background: $medium-gray;
- transform: scale(1.05);
- cursor: pointer;
- }
+ height: 20px;
+ width: 20px;
+ border-radius: 50%;
+ opacity: 0.9;
+ pointer-events: auto;
+ background-color: $dark-gray;
+ color: $white;
+ text-transform: uppercase;
+ letter-spacing: 2px;
+ font-size: 75%;
+ transition: transform 0.2s;
+ text-align: center;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+
+ &:hover {
+ background: $medium-gray;
+ transform: scale(1.05);
+ cursor: pointer;
+ }
}
.templating-menu {
- position: absolute;
- pointer-events: auto;
- text-transform: uppercase;
- letter-spacing: 2px;
- font-size: 75%;
- transition: transform 0.2s;
- text-align: center;
- display: flex;
- justify-content: center;
- align-items: center;
+ position: absolute;
+ pointer-events: auto;
+ text-transform: uppercase;
+ letter-spacing: 2px;
+ font-size: 75%;
+ transition: transform 0.2s;
+ text-align: center;
+ display: flex;
+ justify-content: center;
+ align-items: center;
}
.documentdecorations-icon {
- margin: 0px;
+ margin: 0px;
}
.templating-button,
.docDecs-tagButton {
- width: 20px;
- height: 20px;
- border-radius: 50%;
- opacity: 0.9;
- font-size: 14;
- background-color: $dark-gray;
- color: $white;
- text-align: center;
- cursor: pointer;
-
- &:hover {
- background: $medium-gray;
- transform: scale(1.05);
- }
+ width: 20px;
+ height: 20px;
+ border-radius: 50%;
+ opacity: 0.9;
+ font-size: 14;
+ background-color: $dark-gray;
+ color: $white;
+ text-align: center;
+ cursor: pointer;
+
+ &:hover {
+ background: $medium-gray;
+ transform: scale(1.05);
+ }
}
.documentDecorations-darkScheme {
- background: dimgray;
+ background: dimgray;
}
#template-list {
- position: absolute;
- top: 25px;
- left: 0px;
- width: max-content;
- font-family: $sans-serif;
- font-size: 12px;
- background-color: $light-gray;
- padding: 2px 12px;
- list-style: none;
-
- .templateToggle,
- .chromeToggle {
- text-align: left;
- }
-
- input {
- margin-right: 10px;
- }
+ position: absolute;
+ top: 25px;
+ left: 0px;
+ width: max-content;
+ font-family: $sans-serif;
+ font-size: 12px;
+ background-color: $light-gray;
+ padding: 2px 12px;
+ list-style: none;
+
+ .templateToggle,
+ .chromeToggle {
+ text-align: left;
+ }
+
+ input {
+ margin-right: 10px;
+ }
}
@-moz-keyframes spin {
- 100% {
- -moz-transform: rotate(360deg);
- }
+ 100% {
+ -moz-transform: rotate(360deg);
+ }
}
@-webkit-keyframes spin {
- 100% {
- -webkit-transform: rotate(360deg);
- }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ }
}
@keyframes spin {
- 100% {
- -webkit-transform: rotate(360deg);
- transform: rotate(360deg);
- }
+ 100% {
+ -webkit-transform: rotate(360deg);
+ transform: rotate(360deg);
+ }
}
@keyframes shadow-pulse {
- 0% {
- box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.8);
- }
+ 0% {
+ box-shadow: 0 0 0 0px rgba(0, 0, 0, 0.8);
+ }
- 100% {
- box-shadow: 0 0 0 10px rgba(0, 255, 0, 0);
- }
-} \ No newline at end of file
+ 100% {
+ box-shadow: 0 0 0 10px rgba(0, 255, 0, 0);
+ }
+}
diff --git a/src/client/views/DocumentDecorations.tsx b/src/client/views/DocumentDecorations.tsx
index 6ca8dbec6..5ffdb8ea1 100644
--- a/src/client/views/DocumentDecorations.tsx
+++ b/src/client/views/DocumentDecorations.tsx
@@ -3,15 +3,15 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Tooltip } from '@material-ui/core';
import { action, computed, observable, reaction, runInAction } from "mobx";
import { observer } from "mobx-react";
-import { AclAdmin, AclEdit, DataSym, Doc, Field, HeightSym, WidthSym, DocListCast } from "../../fields/Doc";
+import { DateField } from '../../fields/DateField';
+import { AclAdmin, AclEdit, DataSym, Doc, DocListCast, Field, HeightSym, WidthSym } from "../../fields/Doc";
import { Document } from '../../fields/documentSchemas';
-import { HtmlField } from '../../fields/HtmlField';
import { InkField } from "../../fields/InkField";
import { ScriptField } from '../../fields/ScriptField';
-import { Cast, NumCast, StrCast } from "../../fields/Types";
+import { Cast, NumCast } from "../../fields/Types";
import { GetEffectiveAcl } from '../../fields/util';
-import { setupMoveUpEvents, emptyFunction, returnFalse } from "../../Utils";
-import { Docs, DocUtils } from "../documents/Documents";
+import { emptyFunction, returnFalse, setupMoveUpEvents } from "../../Utils";
+import { Docs } from "../documents/Documents";
import { DocumentType } from '../documents/DocumentTypes';
import { CurrentUserUtils } from '../util/CurrentUserUtils';
import { DragManager } from "../util/DragManager";
@@ -25,12 +25,11 @@ import { KeyManager } from './GlobalKeyHandler';
import { InkStrokeProperties } from './InkStrokeProperties';
import { LightboxView } from './LightboxView';
import { DocumentView } from "./nodes/DocumentView";
-import React = require("react");
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
-import { DateField } from '../../fields/DateField';
+import React = require("react");
@observer
-export class DocumentDecorations extends React.Component<{ boundsLeft: number, boundsTop: number }, { value: string }> {
+export class DocumentDecorations extends React.Component<{ PanelWidth: number, PanelHeight: number, boundsLeft: number, boundsTop: number }, { value: string }> {
static Instance: DocumentDecorations;
private _resizeHdlId = "";
private _keyinput = React.createRef<HTMLInputElement>();
@@ -453,6 +452,7 @@ export class DocumentDecorations extends React.Component<{ boundsLeft: number, b
const borderRadiusDraggerWidth = 15;
bounds.r = Math.max(bounds.x, Math.max(leftBounds, Math.min(window.innerWidth, bounds.r + borderRadiusDraggerWidth + this._resizeBorderWidth / 2) - this._resizeBorderWidth / 2 - borderRadiusDraggerWidth));
bounds.b = Math.max(bounds.y, Math.max(topBounds, Math.min(window.innerHeight, bounds.b + this._resizeBorderWidth / 2 + this._linkBoxHeight) - this._resizeBorderWidth / 2 - this._linkBoxHeight));
+
const useRotation = seldoc.rootDoc.type === DocumentType.INK;
return (<div className="documentDecorations" style={{ background: CurrentUserUtils.ActiveDashboard?.darkScheme ? "dimgray" : "" }} >
diff --git a/src/client/views/GestureOverlay.tsx b/src/client/views/GestureOverlay.tsx
index b401a7f03..6ccbd3fd7 100644
--- a/src/client/views/GestureOverlay.tsx
+++ b/src/client/views/GestureOverlay.tsx
@@ -494,6 +494,7 @@ export class GestureOverlay extends Touchable {
if (InteractionUtils.IsType(e, InteractionUtils.PENTYPE) || [InkTool.Highlighter, InkTool.Pen].includes(CurrentUserUtils.SelectedTool)) {
this._points.push({ X: e.clientX, Y: e.clientY });
setupMoveUpEvents(this, e, this.onPointerMove, this.onPointerUp, emptyFunction);
+ // if (CurrentUserUtils.SelectedTool === InkTool.Highlighter) SetActiveInkColor("rgba(245, 230, 95, 0.75)");
}
}
@@ -688,25 +689,26 @@ export class GestureOverlay extends Touchable {
case "rectangle":
this._points.push({ X: left, Y: top });
this._points.push({ X: left, Y: top });
-
this._points.push({ X: right, Y: top });
this._points.push({ X: right, Y: top });
+
this._points.push({ X: right, Y: top });
this._points.push({ X: right, Y: top });
-
this._points.push({ X: right, Y: bottom });
this._points.push({ X: right, Y: bottom });
+
this._points.push({ X: right, Y: bottom });
this._points.push({ X: right, Y: bottom });
-
this._points.push({ X: left, Y: bottom });
this._points.push({ X: left, Y: bottom });
+
this._points.push({ X: left, Y: bottom });
this._points.push({ X: left, Y: bottom });
-
this._points.push({ X: left, Y: top });
this._points.push({ X: left, Y: top });
+
break;
+
case "triangle":
this._points.push({ X: left, Y: bottom });
this._points.push({ X: left, Y: bottom });
@@ -734,12 +736,8 @@ export class GestureOverlay extends Touchable {
const centerX = (Math.max(left, right) + Math.min(left, right)) / 2;
const centerY = (Math.max(top, bottom) + Math.min(top, bottom)) / 2;
const radius = Math.max(centerX - Math.min(left, right), centerY - Math.min(top, bottom));
- // Dividing the circle into four equal sections, and fitting each section to a cubic Bézier curve.
- this._points.push({ X: centerX - radius, Y: centerY });
- this._points.push({ X: centerX - radius, Y: centerY + (c * radius) });
- this._points.push({ X: centerX - (c * radius), Y: centerY + radius });
- this._points.push({ X: centerX, Y: centerY + radius });
+ // Dividing the circle into four equal sections, and fitting each section to a cubic Bézier curve.
this._points.push({ X: centerX, Y: centerY + radius });
this._points.push({ X: centerX + (c * radius), Y: centerY + radius });
this._points.push({ X: centerX + radius, Y: centerY + (c * radius) });
@@ -755,6 +753,11 @@ export class GestureOverlay extends Touchable {
this._points.push({ X: centerX - radius, Y: centerY - (c * radius) });
this._points.push({ X: centerX - radius, Y: centerY });
+ this._points.push({ X: centerX - radius, Y: centerY });
+ this._points.push({ X: centerX - radius, Y: centerY + (c * radius) });
+ this._points.push({ X: centerX - (c * radius), Y: centerY + radius });
+ this._points.push({ X: centerX, Y: centerY + radius });
+
break;
case "line":
@@ -843,12 +846,12 @@ export class GestureOverlay extends Touchable {
return <svg key={i} width={b.width} height={b.height} style={{ transform: `translate(${b.left}px, ${b.top}px)`, pointerEvents: "none", position: "absolute", zIndex: 30000, overflow: "visible" }}>
{InteractionUtils.CreatePolyline(l, b.left, b.top, ActiveInkColor(), width, width,
ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(),
- ActiveDash(), 1, 1, this.InkShape, "none", false, false)}
+ ActiveDash(), 1, 1, this.InkShape, "none", 1.0, false)}
</svg>;
}),
this._points.length <= 1 ? (null) : <svg key="svg" width={B.width} height={B.height}
style={{ transform: `translate(${B.left}px, ${B.top}px)`, pointerEvents: "none", position: "absolute", zIndex: 30000, overflow: "visible" }}>
- {InteractionUtils.CreatePolyline(this._points.map(p => ({ X: p.X, Y: p.Y - (rect?.y || 0) })), B.left, B.top, ActiveInkColor(), width, width, ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), 1, 1, this.InkShape, "none", false, false)}
+ {InteractionUtils.CreatePolyline(this._points.map(p => ({ X: p.X, Y: p.Y - (rect?.y || 0) })), B.left, B.top, ActiveInkColor(), width, width, ActiveInkBezierApprox(), ActiveFillColor(), ActiveArrowStart(), ActiveArrowEnd(), ActiveDash(), 1, 1, this.InkShape, "none", 1.0, false)}
</svg>]
];
}
diff --git a/src/client/views/InkControls.tsx b/src/client/views/InkControls.tsx
index 6213a4075..4df7ee813 100644
--- a/src/client/views/InkControls.tsx
+++ b/src/client/views/InkControls.tsx
@@ -1,20 +1,22 @@
import React = require("react");
-import { observable, action } from "mobx";
+import { action, observable } from "mobx";
import { observer } from "mobx-react";
-import { InkStrokeProperties } from "./InkStrokeProperties";
-import { setupMoveUpEvents, emptyFunction } from "../../Utils";
-import { UndoManager } from "../util/UndoManager";
-import { ControlPoint, InkData, PointData } from "../../fields/InkField";
-import { Transform } from "../util/Transform";
-import { Colors } from "./global/globalEnums";
import { Doc } from "../../fields/Doc";
+import { ControlPoint, InkData, PointData } from "../../fields/InkField";
import { listSpec } from "../../fields/Schema";
import { Cast } from "../../fields/Types";
+import { setupMoveUpEvents } from "../../Utils";
+import { Transform } from "../util/Transform";
+import { UndoManager } from "../util/UndoManager";
+import { Colors } from "./global/globalEnums";
+import { InkStrokeProperties } from "./InkStrokeProperties";
export interface InkControlProps {
inkDoc: Doc;
- data: InkData;
- addedPoints: PointData[];
+ inkCtrlPoints: InkData;
+ screenCtrlPoints: InkData;
+ inkStrokeSamplePts: PointData[];
+ screenStrokeSamplePoints: PointData[];
format: number[];
ScreenToLocalTransform: () => Transform;
}
@@ -87,56 +89,60 @@ export class InkControls extends React.Component<InkControlProps> {
if (!formatInstance) return (null);
// Accessing the current ink's data and extracting all control points.
- const data = this.props.data;
- const controlPoints: ControlPoint[] = [];
- if (data.length >= 4) {
- for (let i = 0; i <= data.length - 4; i += 4) {
- controlPoints.push({ X: data[i].X, Y: data[i].Y, I: i });
- controlPoints.push({ X: data[i + 3].X, Y: data[i + 3].Y, I: i + 3 });
- }
+ const scrData = this.props.screenCtrlPoints;
+ const sreenCtrlPoints: ControlPoint[] = [];
+ for (let i = 0; i <= scrData.length - 4; i += 4) {
+ sreenCtrlPoints.push({ X: scrData[i].X, Y: scrData[i].Y, I: i });
+ sreenCtrlPoints.push({ X: scrData[i + 3].X, Y: scrData[i + 3].Y, I: i + 3 });
+ }
+
+ const inkData = this.props.inkCtrlPoints;
+ const inkCtrlPts: ControlPoint[] = [];
+ for (let i = 0; i <= inkData.length - 4; i += 4) {
+ inkCtrlPts.push({ X: inkData[i].X, Y: inkData[i].Y, I: i });
+ inkCtrlPts.push({ X: inkData[i + 3].X, Y: inkData[i + 3].Y, I: i + 3 });
}
- const addedPoints = this.props.addedPoints;
- const [left, top, scaleX, scaleY, strokeWidth] = this.props.format;
- return (
- <>
- {addedPoints.map((pts, i) =>
- <svg height="10" width="10" key={`add${i}`}>
- <circle
- cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2}
- cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2}
- r={strokeWidth / 1.5}
- stroke={this._overAddPoint === i ? Colors.MEDIUM_BLUE : "transparent"}
- strokeWidth={0} fill={this._overAddPoint === i ? Colors.MEDIUM_BLUE : "transparent"}
- onPointerDown={() => { formatInstance?.addPoints(pts.X, pts.Y, addedPoints, i, controlPoints); }}
- onMouseEnter={() => this.onEnterAddPoint(i)}
- onMouseLeave={this.onLeaveAddPoint}
- pointerEvents="all"
- cursor="all-scroll"
- />
- </svg>
- )}
- {controlPoints.map((control, i) =>
- <svg height="10" width="10" key={`ctrl${i}`}>
- <rect
- x={(control.X - left - strokeWidth / 2) * scaleX}
- y={(control.Y - top - strokeWidth / 2) * scaleY}
- height={this._overControl === i ? strokeWidth * 1.5 : strokeWidth}
- width={this._overControl === i ? strokeWidth * 1.5 : strokeWidth}
- strokeWidth={strokeWidth / 6} stroke={Colors.MEDIUM_BLUE}
- fill={formatInstance?._currentPoint === control.I ? Colors.MEDIUM_BLUE : Colors.WHITE}
- onPointerDown={(e) => {
- this.changeCurrPoint(control.I);
- this.onControlDown(e, control.I);
- }}
- onMouseEnter={() => this.onEnterControl(i)}
- onMouseLeave={this.onLeaveControl}
- pointerEvents="all"
- cursor="default"
- />
- </svg>
- )}
- </>
+ const [left, top, scaleX, scaleY, strokeWidth, screenSpaceLineWidth] = this.props.format;
+ const rectHdlSize = (i: number) => this._overControl === i ? screenSpaceLineWidth * 6 : screenSpaceLineWidth * 4;
+ return (<svg>
+ {/* should really have just one circle here that represents the neqraest point on the stroke to the users hover point.
+ This points should be passed as a prop from InkingStroke's UI which should set it in its onPointerOver method */}
+ {this.props.screenStrokeSamplePoints.map((pts, i) =>
+ <circle key={i}
+ cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2}
+ cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2}
+ r={screenSpaceLineWidth * 4}
+ fill={this._overAddPoint === i ? "#00007777" : "transparent"}
+ stroke={this._overAddPoint === i ? "#00007777" : "transparent"}
+ strokeWidth={0}
+ onPointerDown={() => formatInstance?.addPoints(this.props.inkStrokeSamplePts[i].X, this.props.inkStrokeSamplePts[i].Y, this.props.inkStrokeSamplePts, i, inkCtrlPts)}
+ onMouseEnter={() => this.onEnterAddPoint(i)}
+ onMouseLeave={this.onLeaveAddPoint}
+ pointerEvents="all"
+ cursor="all-scroll"
+ />
+ )}
+ {sreenCtrlPoints.map((control, i) =>
+ <rect key={i}
+ x={(control.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2 - rectHdlSize(i) / 2}
+ y={(control.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2 - rectHdlSize(i) / 2}
+ height={rectHdlSize(i)}
+ width={rectHdlSize(i)}
+ strokeWidth={screenSpaceLineWidth / 2}
+ stroke={Colors.MEDIUM_BLUE}
+ fill={formatInstance?._currentPoint === control.I ? Colors.MEDIUM_BLUE : Colors.WHITE}
+ onPointerDown={(e) => {
+ this.changeCurrPoint(control.I);
+ this.onControlDown(e, control.I);
+ }}
+ onMouseEnter={() => this.onEnterControl(i)}
+ onMouseLeave={this.onLeaveControl}
+ pointerEvents="all"
+ cursor="default"
+ />
+ )}
+ </svg>
);
}
} \ No newline at end of file
diff --git a/src/client/views/InkHandles.tsx b/src/client/views/InkHandles.tsx
index 0b24c3c32..afe94cdfb 100644
--- a/src/client/views/InkHandles.tsx
+++ b/src/client/views/InkHandles.tsx
@@ -1,22 +1,20 @@
import React = require("react");
-import { observable, action } from "mobx";
+import { action } from "mobx";
import { observer } from "mobx-react";
-import { InkStrokeProperties } from "./InkStrokeProperties";
-import { setupMoveUpEvents, emptyFunction } from "../../Utils";
-import { UndoManager } from "../util/UndoManager";
-import { InkData, HandlePoint, HandleLine } from "../../fields/InkField";
-import { Transform } from "../util/Transform";
import { Doc } from "../../fields/Doc";
-import { listSpec } from "../../fields/Schema";
+import { HandleLine, HandlePoint, InkData } from "../../fields/InkField";
import { List } from "../../fields/List";
+import { listSpec } from "../../fields/Schema";
import { Cast } from "../../fields/Types";
+import { emptyFunction, setupMoveUpEvents } from "../../Utils";
+import { Transform } from "../util/Transform";
+import { UndoManager } from "../util/UndoManager";
import { Colors } from "./global/globalEnums";
-import { GestureOverlay } from "./GestureOverlay";
+import { InkStrokeProperties } from "./InkStrokeProperties";
export interface InkHandlesProps {
inkDoc: Doc;
data: InkData;
- shape?: string;
format: number[];
ScreenToLocalTransform: () => Transform;
}
@@ -70,7 +68,6 @@ export class InkHandles extends React.Component<InkHandlesProps> {
// Accessing the current ink's data and extracting all handle points and handle lines.
const data = this.props.data;
- const shape = this.props.shape;
const handlePoints: HandlePoint[] = [];
const handleLines: HandleLine[] = [];
if (data.length >= 4) {
@@ -85,7 +82,7 @@ export class InkHandles extends React.Component<InkHandlesProps> {
handleLines.push({ X1: data[i].X, Y1: data[i].Y, X2: data[i + 1].X, Y2: data[i + 1].Y, X3: data[i + 3].X, Y3: data[i + 3].Y, dot1: i + 1, dot2: i + 2 });
}
}
- const [left, top, scaleX, scaleY, strokeWidth] = this.props.format;
+ const [left, top, scaleX, scaleY, strokeWidth, screenSpaceLineWidth] = this.props.format;
return (
<>
@@ -94,7 +91,7 @@ export class InkHandles extends React.Component<InkHandlesProps> {
<circle
cx={(pts.X - left - strokeWidth / 2) * scaleX + strokeWidth / 2}
cy={(pts.Y - top - strokeWidth / 2) * scaleY + strokeWidth / 2}
- r={strokeWidth / 2}
+ r={screenSpaceLineWidth * 2}
strokeWidth={0}
fill={Colors.MEDIUM_BLUE}
onPointerDown={(e) => this.onHandleDown(e, pts.I)}
@@ -110,7 +107,7 @@ export class InkHandles extends React.Component<InkHandlesProps> {
x2={(pts.X2 - left - strokeWidth / 2) * scaleX + strokeWidth / 2}
y2={(pts.Y2 - top - strokeWidth / 2) * scaleY + strokeWidth / 2}
stroke={Colors.MEDIUM_BLUE}
- strokeWidth={strokeWidth / 4}
+ strokeWidth={screenSpaceLineWidth}
display={(pts.dot1 === formatInstance._currentPoint || pts.dot2 === formatInstance._currentPoint) ? "inherit" : "none"} />
<line
x1={(pts.X2 - left - strokeWidth / 2) * scaleX + strokeWidth / 2}
@@ -118,7 +115,7 @@ export class InkHandles extends React.Component<InkHandlesProps> {
x2={(pts.X3 - left - strokeWidth / 2) * scaleX + strokeWidth / 2}
y2={(pts.Y3 - top - strokeWidth / 2) * scaleY + strokeWidth / 2}
stroke={Colors.MEDIUM_BLUE}
- strokeWidth={strokeWidth / 4}
+ strokeWidth={screenSpaceLineWidth}
display={(pts.dot1 === formatInstance._currentPoint || pts.dot2 === formatInstance._currentPoint) ? "inherit" : "none"} />
</svg>)}
</>
diff --git a/src/client/views/InkStroke.scss b/src/client/views/InkStroke.scss
index 812a79bd5..53d27cd24 100644
--- a/src/client/views/InkStroke.scss
+++ b/src/client/views/InkStroke.scss
@@ -1,3 +1,17 @@
+.inkstroke-UI {
+ // transform-origin: top left;
+ position: absolute;
+ overflow: visible;
+ pointer-events: none;
+
+ svg:not(:root) {
+ overflow: visible !important;
+ position: absolute;
+ left:0;
+ top:0;
+ }
+}
+
.inkStroke {
mix-blend-mode: multiply;
stroke-linejoin: round;
diff --git a/src/client/views/InkingStroke.tsx b/src/client/views/InkingStroke.tsx
index 282447135..ca39bdaa1 100644
--- a/src/client/views/InkingStroke.tsx
+++ b/src/client/views/InkingStroke.tsx
@@ -14,10 +14,11 @@ import { InteractionUtils } from "../util/InteractionUtils";
import { Scripting } from "../util/Scripting";
import { ContextMenu } from "./ContextMenu";
import { ViewBoxBaseComponent } from "./DocComponent";
-import { GestureOverlay } from "./GestureOverlay";
import { Colors } from "./global/globalEnums";
import { InkControls } from "./InkControls";
import { InkHandles } from "./InkHandles";
+import { GestureOverlay } from "./GestureOverlay";
+import { isThisTypeNode } from "typescript";
import "./InkStroke.scss";
import { InkStrokeProperties } from "./InkStrokeProperties";
import { FieldView, FieldViewProps } from "./nodes/FieldView";
@@ -36,9 +37,11 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
super(props);
this._properties = InkStrokeProperties.Instance;
+ // this._previousColor = ActiveInkColor();
}
componentDidMount() {
+ this.props.setContentView?.(this);
this._selDisposer = reaction(() => this.props.isSelected(), // react to stroke being deselected by turning off ink handles
selected => !selected && this.toggleControlButton());
}
@@ -97,41 +100,104 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
}
}
+ @action
+ checkHighlighter = () => {
+ if (CurrentUserUtils.SelectedTool === InkTool.Highlighter) {
+ // this._previousColor = ActiveInkColor();
+ SetActiveInkColor("rgba(245, 230, 95, 0.75)");
+ }
+ // } else {
+ // SetActiveInkColor(this._previousColor);
+ // }
+ }
+
+ inkScaledData = () => {
+ const inkData: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
+ const inkStrokeWidth = NumCast(this.rootDoc.strokeWidth, 1);
+ const inkTop = Math.min(...inkData.map(p => p.Y)) - inkStrokeWidth / 2;
+ const inkBottom = Math.max(...inkData.map(p => p.Y)) + inkStrokeWidth / 2;
+ const inkLeft = Math.min(...inkData.map(p => p.X)) - inkStrokeWidth / 2;
+ const inkRight = Math.max(...inkData.map(p => p.X)) + inkStrokeWidth / 2;
+ const inkWidth = Math.max(1, inkRight - inkLeft);
+ const inkHeight = Math.max(1, inkBottom - inkTop);
+ return {
+ inkData,
+ inkStrokeWidth,
+ inkTop,
+ inkLeft,
+ inkWidth,
+ inkHeight,
+ inkScaleX: inkHeight === inkStrokeWidth ? 1 : (this.props.PanelWidth() - inkStrokeWidth) / (inkWidth - inkStrokeWidth),
+ inkScaleY: inkWidth === inkStrokeWidth ? 1 : (this.props.PanelHeight() - inkStrokeWidth) / (inkHeight - inkStrokeWidth)
+ };
+ }
+
+ componentUI = (boundsLeft: number, boundsTop: number) => {
+ const inkDoc = this.props.Document;
+ const screenSpaceCenterlineStrokeWidth = 3; // the width of the blue line widget that shows the centerline of the ink stroke
+ const { inkData, inkScaleX, inkScaleY, inkStrokeWidth, inkTop, inkLeft } = this.inkScaledData();
+
+ const screenInkWidth = this.props.ScreenToLocalTransform().inverse().transformDirection(inkStrokeWidth, inkStrokeWidth);
+ const screenPts = inkData.map(point => this.props.ScreenToLocalTransform().inverse().transformPoint(point.X, point.Y)).map(p => ({ X: p[0], Y: p[1] }));
+ const screenTop = Math.min(...screenPts.map(p => p.Y)) - screenInkWidth[0] / 2;
+ const screenLeft = Math.min(...screenPts.map(p => p.X)) - screenInkWidth[0] / 2;
+ const screenOrigin = this.props.ScreenToLocalTransform().inverse().transformPoint(0, 0);
+
+ const screenSpaceSamplePoints = InteractionUtils.CreatePoints(screenPts, screenLeft, screenTop, StrCast(inkDoc.strokeColor, "none"), screenInkWidth[0], screenSpaceCenterlineStrokeWidth,
+ StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker),
+ StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), inkScaleX, inkScaleY, "", "none", this.props.isSelected() && inkStrokeWidth <= 5, false);
+ const inkSpaceSamplePoints = InteractionUtils.CreatePoints(inkData, inkLeft, inkTop, StrCast(inkDoc.strokeColor, "none"), inkStrokeWidth, screenSpaceCenterlineStrokeWidth,
+ StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker),
+ StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), 1, 1, "", "none", this.props.isSelected() && inkStrokeWidth <= 5, false);
+
+ return <div className="inkstroke-UI" style={{
+ left: screenOrigin[0],
+ top: screenOrigin[1],
+ clip: `rect(${boundsTop - screenOrigin[1]}px, 10000px, 10000px, ${boundsLeft - screenOrigin[0]}px)`
+ }} >
+ {InteractionUtils.CreatePolyline(screenPts, screenLeft, screenTop, Colors.MEDIUM_BLUE, screenInkWidth[0], screenSpaceCenterlineStrokeWidth,
+ StrCast(inkDoc.strokeBezier), StrCast(inkDoc.fillColor, "none"),
+ StrCast(inkDoc.strokeStartMarker), StrCast(inkDoc.strokeEndMarker),
+ StrCast(inkDoc.strokeDash), inkScaleX, inkScaleY, "", "none", 1.0, false)}
+ {this._properties?._controlButton ?
+ <>
+ <InkControls
+ inkDoc={inkDoc}
+ inkCtrlPoints={inkData}
+ screenCtrlPoints={screenPts}
+ inkStrokeSamplePts={inkSpaceSamplePoints}
+ screenStrokeSamplePoints={screenSpaceSamplePoints}
+ format={[screenLeft, screenTop, inkScaleX, inkScaleY, screenInkWidth[0], screenSpaceCenterlineStrokeWidth]}
+ ScreenToLocalTransform={this.props.ScreenToLocalTransform} />
+ <InkHandles
+ inkDoc={inkDoc}
+ data={screenPts}
+ format={[screenLeft, screenTop, inkScaleX, inkScaleY, screenInkWidth[0], screenSpaceCenterlineStrokeWidth]}
+ ScreenToLocalTransform={this.props.ScreenToLocalTransform} />
+ </> : ""}
+ </div>;
+ }
+
render() {
TraceMobx();
// Extracting the ink data and formatting information of the current ink stroke.
- // console.log(InkingStroke.InkShape);
- const InkShape = GestureOverlay.Instance.InkShape;
- const data: InkData = Cast(this.dataDoc[this.fieldKey], InkField)?.inkData ?? [];
const inkDoc: Doc = this.layoutDoc;
- const strokeWidth = Number(this.layoutDoc.strokeWidth);
- const lineTop = Math.min(...data.map(p => p.Y));
- const lineBottom = Math.max(...data.map(p => p.Y));
- const lineLeft = Math.min(...data.map(p => p.X));
- const lineRight = Math.max(...data.map(p => p.X));
- const left = lineLeft - strokeWidth / 2;
- const top = lineTop - strokeWidth / 2;
- const right = lineRight + strokeWidth / 2;
- const bottom = lineBottom + strokeWidth / 2;
- const width = Math.max(1, right - left);
- const height = Math.max(1, bottom - top);
- const scaleX = width === strokeWidth ? 1 : (this.props.PanelWidth() - strokeWidth) / (width - strokeWidth);
- const scaleY = height === strokeWidth ? 1 : (this.props.PanelHeight() - strokeWidth) / (height - strokeWidth);
+
+ const { inkData, inkStrokeWidth, inkLeft, inkTop, inkScaleX, inkScaleY, inkWidth, inkHeight } = this.inkScaledData();
+
const strokeColor = StrCast(this.layoutDoc.color, "");
- const dotsize = Math.max(width * scaleX, height * scaleY) / 40;
+ const dotsize = Math.max(inkWidth * inkScaleX, inkHeight * inkScaleY) / 40;
// Visually renders the polygonal line made by the user.
- const inkLine = InteractionUtils.CreatePolyline(data, left, top, strokeColor, strokeWidth, strokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker),
- StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5 && lineBottom - lineTop > 1 && lineRight - lineLeft > 1, false);
+ const inkLine = InteractionUtils.CreatePolyline(inkData, inkLeft, inkTop, strokeColor, inkStrokeWidth, inkStrokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker),
+ StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), inkScaleX, inkScaleY, "", "none", 1.0, false);
// Thin blue line indicating that the current ink stroke is selected.
- const selectedLine = InteractionUtils.CreatePolyline(data, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth / 6, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"),
- StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5 && lineBottom - lineTop > 1 && lineRight - lineLeft > 1, false);
+ // const selectedLine = InteractionUtils.CreatePolyline(data, left, top, Colors.MEDIUM_BLUE, strokeWidth, strokeWidth / 6, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"),
+ // StrCast(this.layoutDoc.strokeStartMarker), StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", 1.0, false);
// Invisible polygonal line that enables the ink to be selected by the user.
- const clickableLine = InteractionUtils.CreatePolyline(data, left, top, "transparent", strokeWidth, strokeWidth + 15, StrCast(this.layoutDoc.strokeBezier),
- StrCast(this.layoutDoc.fillColor, "none"), "none", "none", undefined, scaleX, scaleY, "", this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted", false, true);
+ const clickableLine = InteractionUtils.CreatePolyline(inkData, inkLeft, inkTop, "transparent", inkStrokeWidth, inkStrokeWidth + 15, StrCast(this.layoutDoc.strokeBezier),
+ StrCast(this.layoutDoc.fillColor, "none"), "none", "none", undefined, inkScaleX, inkScaleY, "", this.props.layerProvider?.(this.props.Document) === false ? "none" : "visiblepainted", 0.0, true);
// Set of points rendered upon the ink that can be added if a user clicks on one.
- const addedPoints = InteractionUtils.CreatePoints(data, left, top, strokeColor, strokeWidth, strokeWidth, StrCast(this.layoutDoc.strokeBezier), StrCast(this.layoutDoc.fillColor, "none"), StrCast(this.layoutDoc.strokeStartMarker),
- StrCast(this.layoutDoc.strokeEndMarker), StrCast(this.layoutDoc.strokeDash), scaleX, scaleY, "", "none", this.props.isSelected() && strokeWidth <= 5, false);
return (
<svg className="inkStroke"
@@ -155,22 +221,21 @@ export class InkingStroke extends ViewBoxBaseComponent<FieldViewProps, InkDocume
{clickableLine}
{inkLine}
- {this.props.isSelected() ? selectedLine : ""}
- {this.props.isSelected() && this._properties?._controlButton ?
+ {/* {this.props.isSelected() ? selectedLine : ""} */}
+ {/* {this.props.isSelected() && this._properties?._controlButton ?
<>
<InkControls
inkDoc={inkDoc}
- data={data}
+ data={inkData}
addedPoints={addedPoints}
- format={[left, top, scaleX, scaleY, strokeWidth]}
+ format={[inkLeft, inkTop, inkScaleX, inkScaleY, inkStrokeWidth]}
ScreenToLocalTransform={this.props.ScreenToLocalTransform} />
<InkHandles
inkDoc={inkDoc}
- data={data}
- shape={InkShape}
- format={[left, top, scaleX, scaleY, strokeWidth]}
+ data={inkData}
+ format={[inkLeft, inkTop, inkScaleX, inkScaleY, inkStrokeWidth]}
ScreenToLocalTransform={this.props.ScreenToLocalTransform} />
- </> : ""}
+ </> : ""} */}
</svg>
);
}
diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx
index 9b1cc3499..39a14285a 100644
--- a/src/client/views/MainView.tsx
+++ b/src/client/views/MainView.tsx
@@ -11,6 +11,7 @@ import * as ReactDOM from 'react-dom';
import { Doc, DocListCast, Opt } from '../../fields/Doc';
import { List } from '../../fields/List';
import { PrefetchProxy } from '../../fields/Proxy';
+import { ScriptField } from '../../fields/ScriptField';
import { BoolCast, PromiseValue, StrCast } from '../../fields/Types';
import { TraceMobx } from '../../fields/util';
import { emptyFunction, returnEmptyDoclist, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents, simulateMouseClick, Utils } from '../../Utils';
@@ -36,6 +37,7 @@ import { CollectionLinearView } from './collections/collectionLinear';
import { CollectionMenu } from './collections/CollectionMenu';
import { CollectionViewType } from './collections/CollectionView';
import "./collections/TreeView.scss";
+import { ComponentDecorations } from './ComponentDecorations';
import { ContextMenu } from './ContextMenu';
import { DictationOverlay } from './DictationOverlay';
import { DocumentDecorations } from './DocumentDecorations';
@@ -48,9 +50,11 @@ import { LightboxView } from './LightboxView';
import { LinkMenu } from './linking/LinkMenu';
import "./MainView.scss";
import { AudioBox } from './nodes/AudioBox';
+import { ButtonType } from './nodes/button/FontIconBox';
import { DocumentLinksButton } from './nodes/DocumentLinksButton';
import { DocumentView } from './nodes/DocumentView';
import { FormattedTextBox } from './nodes/formattedText/FormattedTextBox';
+import { RichTextMenu } from './nodes/formattedText/RichTextMenu';
import { LinkDescriptionPopup } from './nodes/LinkDescriptionPopup';
import { LinkDocPreview } from './nodes/LinkDocPreview';
import { RadialMenu } from './nodes/RadialMenu';
@@ -62,9 +66,6 @@ import { PreviewCursor } from './PreviewCursor';
import { PropertiesView } from './PropertiesView';
import { DashboardStyleProvider, DefaultStyleProvider } from './StyleProvider';
import { TopBar } from './topbar/TopBar';
-import { RichTextMenu } from './nodes/formattedText/RichTextMenu';
-import { ScriptField } from '../../fields/ScriptField';
-import { ButtonType } from './nodes/button/FontIconBox';
const _global = (window /* browser */ || global /* node */) as any;
@observer
@@ -81,7 +82,7 @@ export class MainView extends React.Component {
@observable private _sidebarContent: any = this.userDoc?.sidebar;
@observable private _flyoutWidth: number = 0;
- @computed private get topOffset() { return Number(SEARCH_PANEL_HEIGHT.replace("px", "")); } //TODO remove
+ @computed private get topOffset() { return 35 + Number(SEARCH_PANEL_HEIGHT.replace("px", "")); } //TODO remove
@computed private get leftOffset() { return this.menuPanelWidth() - 2; }
@computed private get userDoc() { return Doc.UserDoc(); }
@computed private get darkScheme() { return BoolCast(CurrentUserUtils.ActiveDashboard?.darkScheme); }
@@ -602,7 +603,8 @@ export class MainView extends React.Component {
<CaptureManager />
<GroupManager />
<GoogleAuthenticationManager />
- <DocumentDecorations boundsLeft={this.leftOffset} boundsTop={this.topOffset} />
+ <DocumentDecorations PanelWidth={this._windowWidth} PanelHeight={this._windowHeight} boundsLeft={this.leftOffset} boundsTop={this.topOffset} />
+ <ComponentDecorations boundsLeft={this.leftOffset} boundsTop={this.topOffset + 25} />
{this.topbar}
{LinkDescriptionPopup.descriptionPopup ? <LinkDescriptionPopup /> : null}
{DocumentLinksButton.LinkEditorDocView ? <LinkMenu docView={DocumentLinksButton.LinkEditorDocView} changeFlyout={emptyFunction} /> : (null)}
diff --git a/src/client/views/collections/CollectionMenu.tsx b/src/client/views/collections/CollectionMenu.tsx
index aefa1ec3d..6ffa6c279 100644
--- a/src/client/views/collections/CollectionMenu.tsx
+++ b/src/client/views/collections/CollectionMenu.tsx
@@ -677,12 +677,12 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
private _palette = ["#D0021B", "#F5A623", "#F8E71C", "#8B572A", "#7ED321", "#417505", "#9013FE", "#4A90E2", "#50E3C2", "#B8E986", "#000000", "#4A4A4A", "#9B9B9B", "#FFFFFF", ""];
private _width = ["1", "5", "10", "100"];
private _dotsize = [10, 20, 30, 40];
- private _draw = ["∿", "⎯", "→", "↔︎", "ロ", "O"];
- private _head = ["", "", "", "arrow", "", ""];
- private _end = ["", "", "arrow", "arrow", "", ""];
- private _shapePrims = ["", "line", "line", "line", "rectangle", "circle"];
- private _title = ["pen", "line", "line with arrow", "line with double arrows", "square", "circle",];
- private _faName = ["pen-fancy", "minus", "long-arrow-alt-right", "arrows-alt-h", "square", "circle"];
+ private _draw = ["∿", "=", "⎯", "→", "↔︎", "ロ", "O"];
+ private _head = ["", "", "", "", "arrow", "", ""];
+ private _end = ["", "", "", "arrow", "arrow", "", ""];
+ private _shapePrims = ["", "", "line", "line", "line", "rectangle", "circle"];
+ private _title = ["pen", "highlighter", "line", "line with arrow", "line with double arrows", "square", "circle"];
+ private _faName = ["pen-fancy", "highlighter", "minus", "long-arrow-alt-right", "arrows-alt-h", "square", "circle"];
@observable _selectedPrimitive = this._shapePrims.length;
@observable _keepPrimitiveMode = false; // for whether primitive selection enters a one-shot or persistent mode
@observable _colorBtn = false;
@@ -692,6 +692,7 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
@action clearKeepPrimitiveMode() { this._selectedPrimitive = this._shapePrims.length; }
@action primCreated() {
if (!this._keepPrimitiveMode) { //get out of ink mode after each stroke=
+ if (CurrentUserUtils.SelectedTool === InkTool.Highlighter && GestureOverlay.Instance.SavedColor) SetActiveInkColor(GestureOverlay.Instance.SavedColor);
CurrentUserUtils.SelectedTool = InkTool.None;
this._selectedPrimitive = this._shapePrims.length;
SetActiveArrowStart("none");
@@ -732,7 +733,13 @@ export class CollectionFreeFormViewChrome extends React.Component<CollectionMenu
this._keepPrimitiveMode = keep;
if (this._selectedPrimitive !== i) {
this._selectedPrimitive = i;
- CurrentUserUtils.SelectedTool = InkTool.Pen;
+ if (this._title[i] === "highlighter") {
+ CurrentUserUtils.SelectedTool = InkTool.Highlighter;
+ GestureOverlay.Instance.SavedColor = ActiveInkColor();
+ SetActiveInkColor("rgba(245, 230, 95, 0.75)");
+ } else {
+ CurrentUserUtils.SelectedTool = InkTool.Pen;
+ }
SetActiveArrowStart(this._head[i]);
SetActiveArrowEnd(this._end[i]);
SetActiveBezierApprox("300");
diff --git a/src/client/views/nodes/DocumentView.tsx b/src/client/views/nodes/DocumentView.tsx
index 193befa5d..5ef49bd3b 100644
--- a/src/client/views/nodes/DocumentView.tsx
+++ b/src/client/views/nodes/DocumentView.tsx
@@ -91,6 +91,7 @@ export interface DocComponentView {
setKeyFrameEditing?: (set: boolean) => void; // whether the document is in keyframe editing mode (if it is, then all hidden documents that are not active at the keyframe time will still be shown)
playFrom?: (time: number, endTime?: number) => void;
setFocus?: () => void;
+ componentUI?: (boundsLeft: number, boundsTop: number) => JSX.Element;
fieldKey?: string;
annotationKey?: string;
getTitle?: () => string;
diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx
index dbd641550..9c353e9d0 100644
--- a/src/client/views/search/SearchBox.tsx
+++ b/src/client/views/search/SearchBox.tsx
@@ -301,7 +301,7 @@ export class SearchBox extends ViewBoxBaseComponent<SearchBoxProps, SearchBoxDoc
}
const formattedType = SearchBox.formatType(StrCast(result[0].type));
- const title = result[0].title
+ const title = result[0].title;
if (this._docTypeString === "all" || this._docTypeString === result[0].type) {
validResults++;