From 59225938cafe9abcc09c34f0c6d81d40ceda8bed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20ROU=C3=8BN=C3=89?= Date: Mon, 18 Mar 2024 16:10:07 +0100 Subject: [PATCH] [3253] Add a new tool to the group palette to apply same size on multiple nodes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug: https://github.com/eclipse-sirius/sirius-web/issues/3253 Signed-off-by: Florian ROUËNÉ --- CHANGELOG.adoc | 1 + .../e2e/project/diagrams/group-palette.cy.ts | 1 + .../renderer/layout/useDistributeElements.ts | 143 +++++++++++------- .../layout/useDistributeElements.types.ts | 1 + .../palette/group-tool/GroupPalette.tsx | 8 + 5 files changed, 102 insertions(+), 52 deletions(-) diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index fa58703444..f8bf4bc222 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -149,6 +149,7 @@ Form variables declared in a form description will thus be added in the FormDesc - https://github.com/eclipse-sirius/sirius-web/issues/3198[#3198] [form] Add a new variable, `variableManager`, in most interpreted expressions of the form DSL. - https://github.com/eclipse-sirius/sirius-web/issues/3243[#3243] [diagram] Add tools to help manual layout on multiple elements - https://github.com/eclipse-sirius/sirius-web/issues/2999[#2999] [formdescriptioneditor] Add the support for read-only _Form Description Editors_. +- https://github.com/eclipse-sirius/sirius-web/issues/3253[#3253] [diagram] Add a new tool to apply same size on multiple nodes === Improvements diff --git a/integration-tests/cypress/e2e/project/diagrams/group-palette.cy.ts b/integration-tests/cypress/e2e/project/diagrams/group-palette.cy.ts index 8c9fa2c34d..f35b2a201f 100644 --- a/integration-tests/cypress/e2e/project/diagrams/group-palette.cy.ts +++ b/integration-tests/cypress/e2e/project/diagrams/group-palette.cy.ts @@ -80,6 +80,7 @@ describe('Diagram - group palette', () => { diagram.getGroupPalette().findByTestId('Arrange in row').should('exist'); diagram.getGroupPalette().findByTestId('Arrange in column').should('exist'); diagram.getGroupPalette().findByTestId('Arrange in grid').should('exist'); + diagram.getGroupPalette().findByTestId('Make same size').should('exist'); }); it('Then the last distribute elements tool used is memorized', () => { diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/layout/useDistributeElements.ts b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/layout/useDistributeElements.ts index ed4b12909b..4f4d56b98b 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/layout/useDistributeElements.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/layout/useDistributeElements.ts @@ -111,7 +111,7 @@ export const useDistributeElements = (refreshEventPayloadId: string): UseDistrib totalSize) / numberOfGap; const updatedNodes = getNodes().map((node) => { - if (!selectedNodeIds.includes(node.id)) { + if (!selectedNodeIds.includes(node.id) || node.data.pinned) { return node; } @@ -152,10 +152,9 @@ export const useDistributeElements = (refreshEventPayloadId: string): UseDistrib return useCallback((selectedNodeIds: string[], refElementId: string | null) => { processLayoutTool( selectedNodeIds, - (selectedNodes, refNode) => { - selectedNodes.sort(getComparePositionFn('horizontal')); + (_selectedNodes, refNode) => { return getNodes().map((node) => { - if (!selectedNodeIds.includes(node.id)) { + if (!selectedNodeIds.includes(node.id) || node.data.pinned) { return node; } const referencePositionValue: number = (() => { @@ -223,7 +222,11 @@ export const useDistributeElements = (refreshEventPayloadId: string): UseDistrib (selectedNodes: Node[], selectedNodeIds: string[], refNode: Node): Node[] => { const largestWidth: number = selectedNodes.reduce((width, node) => Math.max(width, node.width ?? 0), 0); return getNodes().map((node) => { - if (!selectedNodeIds.includes(node.id)) { + if ( + !selectedNodeIds.includes(node.id) || + node.data.nodeDescription?.userResizable === false || + node.data.pinned + ) { return node; } return { @@ -246,7 +249,11 @@ export const useDistributeElements = (refreshEventPayloadId: string): UseDistrib (selectedNodes: Node[], selectedNodeIds: string[], refNode: Node): Node[] => { const largestHeight: number = selectedNodes.reduce((height, node) => Math.max(height, node.height ?? 0), 0); return getNodes().map((node) => { - if (!selectedNodeIds.includes(node.id)) { + if ( + !selectedNodeIds.includes(node.id) || + node.data.nodeDescription?.userResizable === false || + node.data.pinned + ) { return node; } return { @@ -270,18 +277,20 @@ export const useDistributeElements = (refreshEventPayloadId: string): UseDistrib selectedNodeIds, (selectedNodes, refNode) => { let nextXPosition: number = refNode.position.x; - const updatedSelectedNodes = selectedNodes.map((node) => { - const updatedNode = { - ...node, - position: { - ...node.position, - x: nextXPosition, - y: refNode.position.y, - }, - }; - nextXPosition = updatedNode.position.x + (updatedNode.width ?? 0) + arrangeGapBetweenElements; - return updatedNode; - }); + const updatedSelectedNodes = selectedNodes + .filter((node) => !node.data.pinned) + .map((node) => { + const updatedNode = { + ...node, + position: { + ...node.position, + x: nextXPosition, + y: refNode.position.y, + }, + }; + nextXPosition = updatedNode.position.x + (updatedNode.width ?? 0) + arrangeGapBetweenElements; + return updatedNode; + }); return getNodes().map((node) => { const replacedNode = updatedSelectedNodes.find((updatedSelectedNode) => updatedSelectedNode.id === node.id); @@ -300,18 +309,20 @@ export const useDistributeElements = (refreshEventPayloadId: string): UseDistrib selectedNodeIds, (selectedNodes, refNode) => { let nextYPosition: number = refNode.position.y; - const updatedSelectedNodes = selectedNodes.map((node) => { - const updatedNode = { - ...node, - position: { - ...node.position, - x: refNode.position.x, - y: nextYPosition, - }, - }; - nextYPosition = updatedNode.position.y + (updatedNode.height ?? 0) + arrangeGapBetweenElements; - return updatedNode; - }); + const updatedSelectedNodes = selectedNodes + .filter((node) => !node.data.pinned) + .map((node) => { + const updatedNode = { + ...node, + position: { + ...node.position, + x: refNode.position.x, + y: nextYPosition, + }, + }; + nextYPosition = updatedNode.position.y + (updatedNode.height ?? 0) + arrangeGapBetweenElements; + return updatedNode; + }); return getNodes().map((node) => { const replacedNode = updatedSelectedNodes.find((updatedSelectedNode) => updatedSelectedNode.id === node.id); @@ -332,28 +343,30 @@ export const useDistributeElements = (refreshEventPayloadId: string): UseDistrib const columnNumber: number = Math.round(Math.sqrt(selectedNodeIds.length)); let nextXPosition: number = refNode.position.x; let nextYPosition: number = refNode.position.y; - const updatedSelectedNodes = selectedNodes.map((node, index) => { - const columnIndex = index + 1; - const updatedNode = { - ...node, - position: { - ...node.position, - x: nextXPosition, - y: nextYPosition, - }, - }; - nextXPosition = updatedNode.position.x + (updatedNode.width ?? 0) + arrangeGapBetweenElements; - if (columnIndex % columnNumber === 0) { - nextXPosition = refNode.position.x; - nextYPosition = - updatedNode.position.y + - arrangeGapBetweenElements + - selectedNodes - .slice(columnIndex - columnNumber, columnIndex) - .reduce((maxHeight, rowNode) => Math.max(maxHeight, rowNode.height ?? 0), 0); - } - return updatedNode; - }); + const updatedSelectedNodes = selectedNodes + .filter((node) => !node.data.pinned) + .map((node, index) => { + const columnIndex = index + 1; + const updatedNode = { + ...node, + position: { + ...node.position, + x: nextXPosition, + y: nextYPosition, + }, + }; + nextXPosition = updatedNode.position.x + (updatedNode.width ?? 0) + arrangeGapBetweenElements; + if (columnIndex % columnNumber === 0) { + nextXPosition = refNode.position.x; + nextYPosition = + updatedNode.position.y + + arrangeGapBetweenElements + + selectedNodes + .slice(columnIndex - columnNumber, columnIndex) + .reduce((maxHeight, rowNode) => Math.max(maxHeight, rowNode.height ?? 0), 0); + } + return updatedNode; + }); return getNodes().map((node) => { const replacedNode = updatedSelectedNodes.find((updatedSelectedNode) => updatedSelectedNode.id === node.id); @@ -376,6 +389,31 @@ export const useDistributeElements = (refreshEventPayloadId: string): UseDistrib const distributeAlignBottom = distributeAlign('bottom'); const distributeAlignMiddle = distributeAlign('middle'); + const makeNodesSameSize = useCallback((selectedNodeIds: string[], refElementId: string | null) => { + processLayoutTool( + selectedNodeIds, + (_selectedNodes, refNode) => { + return getNodes().map((node) => { + if (!selectedNodeIds.includes(node.id) || node.data.nodeDescription?.userResizable === false) { + return node; + } + + return { + ...node, + width: refNode.width, + height: refNode.height, + data: { + ...node.data, + resizedByUser: true, + }, + }; + }); + }, + null, + refElementId + ); + }, []); + return { distributeGapVertically, distributeGapHorizontally, @@ -390,5 +428,6 @@ export const useDistributeElements = (refreshEventPayloadId: string): UseDistrib arrangeInRow, arrangeInColumn, arrangeInGrid, + makeNodesSameSize, }; }; diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/layout/useDistributeElements.types.ts b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/layout/useDistributeElements.types.ts index 2d90b2ccba..bfdb39fc45 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/layout/useDistributeElements.types.ts +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/layout/useDistributeElements.types.ts @@ -25,4 +25,5 @@ export interface UseDistributeElementsValue { arrangeInRow: (selectedNodeIds: string[]) => void; arrangeInColumn: (selectedNodeIds: string[]) => void; arrangeInGrid: (selectedNodeIds: string[]) => void; + makeNodesSameSize: (selectedNodeIds: string[], refElementId: string | null) => void; } diff --git a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/palette/group-tool/GroupPalette.tsx b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/palette/group-tool/GroupPalette.tsx index b73e5d3451..092e2c10a4 100644 --- a/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/palette/group-tool/GroupPalette.tsx +++ b/packages/diagrams/frontend/sirius-components-diagrams/src/renderer/palette/group-tool/GroupPalette.tsx @@ -13,6 +13,7 @@ import Paper from '@material-ui/core/Paper'; import { makeStyles } from '@material-ui/core/styles'; +import PhotoSizeSelectSmallIcon from '@material-ui/icons/PhotoSizeSelectSmall'; import ClickAwayListener from '@material-ui/core/ClickAwayListener'; import Popper from '@material-ui/core/Popper'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; @@ -99,6 +100,7 @@ export const GroupPalette = memo( arrangeInRow, arrangeInColumn, arrangeInGrid, + makeNodesSameSize, } = useDistributeElements(refreshEventPayloadId); const [selectedElementIds, setSelectedElementIds] = useState([]); const [state, setState] = useState({ @@ -201,6 +203,12 @@ export const GroupPalette = memo( action: () => arrangeInGrid(selectedElementIds), icon: , }, + { + id: 'make-same-size', + title: 'Make same size', + action: () => makeNodesSameSize(selectedElementIds, refElementId), + icon: , + }, ]; const shouldRender = selectedElementIds.length > 1 && isOpened && x && y; if (!shouldRender) {