|
@@ -31,6 +31,7 @@ import {
|
|
actionBindText,
|
|
actionBindText,
|
|
actionUngroup,
|
|
actionUngroup,
|
|
actionLink,
|
|
actionLink,
|
|
|
|
+ actionToggleLock,
|
|
} from "../actions";
|
|
} from "../actions";
|
|
import { createRedoAction, createUndoAction } from "../actions/actionHistory";
|
|
import { createRedoAction, createUndoAction } from "../actions/actionHistory";
|
|
import { ActionManager } from "../actions/manager";
|
|
import { ActionManager } from "../actions/manager";
|
|
@@ -1134,7 +1135,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
prevState.activeTool !== this.state.activeTool &&
|
|
prevState.activeTool !== this.state.activeTool &&
|
|
multiElement != null &&
|
|
multiElement != null &&
|
|
isBindingEnabled(this.state) &&
|
|
isBindingEnabled(this.state) &&
|
|
- isBindingElement(multiElement)
|
|
|
|
|
|
+ isBindingElement(multiElement, false)
|
|
) {
|
|
) {
|
|
maybeBindLinearElement(
|
|
maybeBindLinearElement(
|
|
multiElement,
|
|
multiElement,
|
|
@@ -1546,6 +1547,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
fontFamily: this.state.currentItemFontFamily,
|
|
fontFamily: this.state.currentItemFontFamily,
|
|
textAlign: this.state.currentItemTextAlign,
|
|
textAlign: this.state.currentItemTextAlign,
|
|
verticalAlign: DEFAULT_VERTICAL_ALIGN,
|
|
verticalAlign: DEFAULT_VERTICAL_ALIGN,
|
|
|
|
+ locked: false,
|
|
});
|
|
});
|
|
|
|
|
|
this.scene.replaceAllElements([
|
|
this.scene.replaceAllElements([
|
|
@@ -2126,12 +2128,14 @@ class App extends React.Component<AppProps, AppState> {
|
|
of all hit elements */
|
|
of all hit elements */
|
|
preferSelected?: boolean;
|
|
preferSelected?: boolean;
|
|
includeBoundTextElement?: boolean;
|
|
includeBoundTextElement?: boolean;
|
|
|
|
+ includeLockedElements?: boolean;
|
|
},
|
|
},
|
|
): NonDeleted<ExcalidrawElement> | null {
|
|
): NonDeleted<ExcalidrawElement> | null {
|
|
const allHitElements = this.getElementsAtPosition(
|
|
const allHitElements = this.getElementsAtPosition(
|
|
x,
|
|
x,
|
|
y,
|
|
y,
|
|
opts?.includeBoundTextElement,
|
|
opts?.includeBoundTextElement,
|
|
|
|
+ opts?.includeLockedElements,
|
|
);
|
|
);
|
|
if (allHitElements.length > 1) {
|
|
if (allHitElements.length > 1) {
|
|
if (opts?.preferSelected) {
|
|
if (opts?.preferSelected) {
|
|
@@ -2164,14 +2168,19 @@ class App extends React.Component<AppProps, AppState> {
|
|
x: number,
|
|
x: number,
|
|
y: number,
|
|
y: number,
|
|
includeBoundTextElement: boolean = false,
|
|
includeBoundTextElement: boolean = false,
|
|
|
|
+ includeLockedElements: boolean = false,
|
|
): NonDeleted<ExcalidrawElement>[] {
|
|
): NonDeleted<ExcalidrawElement>[] {
|
|
- const elements = includeBoundTextElement
|
|
|
|
- ? this.scene.getElements()
|
|
|
|
- : this.scene
|
|
|
|
- .getElements()
|
|
|
|
- .filter(
|
|
|
|
- (element) => !(isTextElement(element) && element.containerId),
|
|
|
|
- );
|
|
|
|
|
|
+ const elements =
|
|
|
|
+ includeBoundTextElement && includeLockedElements
|
|
|
|
+ ? this.scene.getElements()
|
|
|
|
+ : this.scene
|
|
|
|
+ .getElements()
|
|
|
|
+ .filter(
|
|
|
|
+ (element) =>
|
|
|
|
+ (includeLockedElements || !element.locked) &&
|
|
|
|
+ (includeBoundTextElement ||
|
|
|
|
+ !(isTextElement(element) && element.containerId)),
|
|
|
|
+ );
|
|
|
|
|
|
return getElementsAtPosition(elements, (element) =>
|
|
return getElementsAtPosition(elements, (element) =>
|
|
hitTest(element, this.state, x, y),
|
|
hitTest(element, this.state, x, y),
|
|
@@ -2213,7 +2222,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
if (selectedElements.length === 1) {
|
|
if (selectedElements.length === 1) {
|
|
if (isTextElement(selectedElements[0])) {
|
|
if (isTextElement(selectedElements[0])) {
|
|
existingTextElement = selectedElements[0];
|
|
existingTextElement = selectedElements[0];
|
|
- } else if (isTextBindableContainer(selectedElements[0])) {
|
|
|
|
|
|
+ } else if (isTextBindableContainer(selectedElements[0], false)) {
|
|
container = selectedElements[0];
|
|
container = selectedElements[0];
|
|
existingTextElement = getBoundTextElement(container);
|
|
existingTextElement = getBoundTextElement(container);
|
|
}
|
|
}
|
|
@@ -2233,7 +2242,8 @@ class App extends React.Component<AppProps, AppState> {
|
|
this.scene
|
|
this.scene
|
|
.getElements()
|
|
.getElements()
|
|
.filter(
|
|
.filter(
|
|
- (ele) => isTextBindableContainer(ele) && !getBoundTextElement(ele),
|
|
|
|
|
|
+ (ele) =>
|
|
|
|
+ isTextBindableContainer(ele, false) && !getBoundTextElement(ele),
|
|
),
|
|
),
|
|
sceneX,
|
|
sceneX,
|
|
sceneY,
|
|
sceneY,
|
|
@@ -2291,6 +2301,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
: DEFAULT_VERTICAL_ALIGN,
|
|
: DEFAULT_VERTICAL_ALIGN,
|
|
containerId: container?.id ?? undefined,
|
|
containerId: container?.id ?? undefined,
|
|
groupIds: container?.groupIds ?? [],
|
|
groupIds: container?.groupIds ?? [],
|
|
|
|
+ locked: false,
|
|
});
|
|
});
|
|
|
|
|
|
this.setState({ editingElement: element });
|
|
this.setState({ editingElement: element });
|
|
@@ -2597,7 +2608,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
// Hovering with a selected tool or creating new linear element via click
|
|
// Hovering with a selected tool or creating new linear element via click
|
|
// and point
|
|
// and point
|
|
const { draggingElement } = this.state;
|
|
const { draggingElement } = this.state;
|
|
- if (isBindingElement(draggingElement)) {
|
|
|
|
|
|
+ if (isBindingElement(draggingElement, false)) {
|
|
this.maybeSuggestBindingsForLinearElementAtCoords(
|
|
this.maybeSuggestBindingsForLinearElementAtCoords(
|
|
draggingElement,
|
|
draggingElement,
|
|
[scenePointer],
|
|
[scenePointer],
|
|
@@ -2780,7 +2791,8 @@ class App extends React.Component<AppProps, AppState> {
|
|
this.isHittingCommonBoundingBoxOfSelectedElements(
|
|
this.isHittingCommonBoundingBoxOfSelectedElements(
|
|
scenePointer,
|
|
scenePointer,
|
|
selectedElements,
|
|
selectedElements,
|
|
- ))
|
|
|
|
|
|
+ )) &&
|
|
|
|
+ !hitElement?.locked
|
|
) {
|
|
) {
|
|
setCursor(this.canvas, CURSOR_TYPE.MOVE);
|
|
setCursor(this.canvas, CURSOR_TYPE.MOVE);
|
|
} else {
|
|
} else {
|
|
@@ -2796,6 +2808,10 @@ class App extends React.Component<AppProps, AppState> {
|
|
) => {
|
|
) => {
|
|
const updateElementIds = (elements: ExcalidrawElement[]) => {
|
|
const updateElementIds = (elements: ExcalidrawElement[]) => {
|
|
elements.forEach((element) => {
|
|
elements.forEach((element) => {
|
|
|
|
+ if (element.locked) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
idsToUpdate.push(element.id);
|
|
idsToUpdate.push(element.id);
|
|
if (event.altKey) {
|
|
if (event.altKey) {
|
|
if (
|
|
if (
|
|
@@ -3617,6 +3633,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
opacity: this.state.currentItemOpacity,
|
|
opacity: this.state.currentItemOpacity,
|
|
strokeSharpness: this.state.currentItemLinearStrokeSharpness,
|
|
strokeSharpness: this.state.currentItemLinearStrokeSharpness,
|
|
simulatePressure: event.pressure === 0.5,
|
|
simulatePressure: event.pressure === 0.5,
|
|
|
|
+ locked: false,
|
|
});
|
|
});
|
|
|
|
|
|
this.setState((prevState) => ({
|
|
this.setState((prevState) => ({
|
|
@@ -3672,6 +3689,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
roughness: this.state.currentItemRoughness,
|
|
roughness: this.state.currentItemRoughness,
|
|
opacity: this.state.currentItemOpacity,
|
|
opacity: this.state.currentItemOpacity,
|
|
strokeSharpness: this.state.currentItemLinearStrokeSharpness,
|
|
strokeSharpness: this.state.currentItemLinearStrokeSharpness,
|
|
|
|
+ locked: false,
|
|
});
|
|
});
|
|
|
|
|
|
return element;
|
|
return element;
|
|
@@ -3759,6 +3777,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
strokeSharpness: this.state.currentItemLinearStrokeSharpness,
|
|
strokeSharpness: this.state.currentItemLinearStrokeSharpness,
|
|
startArrowhead,
|
|
startArrowhead,
|
|
endArrowhead,
|
|
endArrowhead,
|
|
|
|
+ locked: false,
|
|
});
|
|
});
|
|
this.setState((prevState) => ({
|
|
this.setState((prevState) => ({
|
|
selectedElementIds: {
|
|
selectedElementIds: {
|
|
@@ -3807,6 +3826,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
roughness: this.state.currentItemRoughness,
|
|
roughness: this.state.currentItemRoughness,
|
|
opacity: this.state.currentItemOpacity,
|
|
opacity: this.state.currentItemOpacity,
|
|
strokeSharpness: this.state.currentItemStrokeSharpness,
|
|
strokeSharpness: this.state.currentItemStrokeSharpness,
|
|
|
|
+ locked: false,
|
|
});
|
|
});
|
|
|
|
|
|
if (element.type === "selection") {
|
|
if (element.type === "selection") {
|
|
@@ -4106,7 +4126,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
- if (isBindingElement(draggingElement)) {
|
|
|
|
|
|
+ if (isBindingElement(draggingElement, false)) {
|
|
// When creating a linear element by dragging
|
|
// When creating a linear element by dragging
|
|
this.maybeSuggestBindingsForLinearElementAtCoords(
|
|
this.maybeSuggestBindingsForLinearElementAtCoords(
|
|
draggingElement,
|
|
draggingElement,
|
|
@@ -4385,7 +4405,7 @@ class App extends React.Component<AppProps, AppState> {
|
|
} else if (pointerDownState.drag.hasOccurred && !multiElement) {
|
|
} else if (pointerDownState.drag.hasOccurred && !multiElement) {
|
|
if (
|
|
if (
|
|
isBindingEnabled(this.state) &&
|
|
isBindingEnabled(this.state) &&
|
|
- isBindingElement(draggingElement)
|
|
|
|
|
|
+ isBindingElement(draggingElement, false)
|
|
) {
|
|
) {
|
|
maybeBindLinearElement(
|
|
maybeBindLinearElement(
|
|
draggingElement,
|
|
draggingElement,
|
|
@@ -5303,7 +5323,10 @@ class App extends React.Component<AppProps, AppState> {
|
|
}
|
|
}
|
|
|
|
|
|
const { x, y } = viewportCoordsToSceneCoords(event, this.state);
|
|
const { x, y } = viewportCoordsToSceneCoords(event, this.state);
|
|
- const element = this.getElementAtPosition(x, y, { preferSelected: true });
|
|
|
|
|
|
+ const element = this.getElementAtPosition(x, y, {
|
|
|
|
+ preferSelected: true,
|
|
|
|
+ includeLockedElements: true,
|
|
|
|
+ });
|
|
|
|
|
|
const type = element ? "element" : "canvas";
|
|
const type = element ? "element" : "canvas";
|
|
|
|
|
|
@@ -5615,6 +5638,8 @@ class App extends React.Component<AppProps, AppState> {
|
|
(maybeFlipHorizontal || maybeFlipVertical) && separator,
|
|
(maybeFlipHorizontal || maybeFlipVertical) && separator,
|
|
actionLink.contextItemPredicate(elements, this.state) && actionLink,
|
|
actionLink.contextItemPredicate(elements, this.state) && actionLink,
|
|
actionDuplicateSelection,
|
|
actionDuplicateSelection,
|
|
|
|
+ actionToggleLock,
|
|
|
|
+ separator,
|
|
actionDeleteSelected,
|
|
actionDeleteSelected,
|
|
],
|
|
],
|
|
top,
|
|
top,
|