Skip to content

Commit

Permalink
[3201] Add support for tools on multiple diagram elements (hide, fade…
Browse files Browse the repository at this point in the history
… and pin)

Bug: #3201
Signed-off-by: Florian ROUËNÉ <florian.rouene@obeosoft.com>
  • Loading branch information
frouene committed Mar 11, 2024
1 parent 814a19d commit e9eff1d
Show file tree
Hide file tree
Showing 6 changed files with 247 additions and 7 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ image:doc/screenshots/showDeletionConfirmation.png[Deletion Confirmation Dialog,
- https://github.com/eclipse-sirius/sirius-web/issues/3193[#3193] [core] Added the methods `hasVariable(String name)` and `getParent()` in VariableManager to, respectively, detect if a variable manager defines a variable (it returns `false`, if the variable is defined by a parent `VariableManager`) and to navigate to a parent `VariableManager`.
Thanks to this capability, a specifier can easily retrieve a variable overriden by a child `VariableManager`.
- https://github.com/eclipse-sirius/sirius-web/issues/3096[#3096] [tree] Tree representations can now support filters

- https://github.com/eclipse-sirius/sirius-web/issues/3201[#3201] [diagram] Add support for tools on multiple diagram elements (hide, fade and pin).

=== Improvements

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import { useSynchronizeLayoutData } from './layout/useSynchronizeLayoutData';
import { useMoveChange } from './move/useMoveChange';
import { DiagramNodeType } from './node/NodeTypes.types';
import { useNodeType } from './node/useNodeType';
import { GroupPalette } from './palette/group-tool/GroupPalette';
import { DiagramPalette } from './palette/DiagramPalette';
import { useDiagramElementPalette } from './palette/useDiagramElementPalette';
import { useDiagramPalette } from './palette/useDiagramPalette';
Expand All @@ -72,6 +73,7 @@ import { useDiagramSelection } from './selection/useDiagramSelection';
import { useSnapToGrid } from './snap-to-grid/useSnapToGrid';

import 'reactflow/dist/style.css';
import { useGroupPalette } from './palette/group-tool/useGroupPalette';

const GRID_STEP: number = 10;

Expand All @@ -92,6 +94,13 @@ export const DiagramRenderer = ({ diagramRefreshedEventPayload }: DiagramRendere
isOpened: isDiagramElementPaletteOpened,
} = useDiagramElementPalette();

const {
onDiagramGroupElementClick,
hideGroupPalette,
position: groupPalettePosition,
isOpened: isGroupPaletteOpened,
} = useGroupPalette();

const { onConnect, onConnectStart, onConnectEnd } = useConnector();
const { reconnectEdge } = useReconnectEdge();
const { onDrop, onDragOver } = useDrop();
Expand Down Expand Up @@ -131,8 +140,7 @@ export const DiagramRenderer = ({ diagramRefreshedEventPayload }: DiagramRendere

setNodes(laidOutDiagram.nodes);
setEdges(laidOutDiagram.edges);
hideDiagramPalette();
hideDiagramElementPalette();
closeAllPalettes();

synchronizeLayoutData(diagramRefreshedEventPayload.id, laidOutDiagram);
});
Expand Down Expand Up @@ -173,7 +181,7 @@ export const DiagramRenderer = ({ diagramRefreshedEventPayload }: DiagramRendere
transformedNodeChanges = applyHelperLines(transformedNodeChanges);

if (transformedNodeChanges.some((change) => change.type === 'position')) {
hideDiagramElementPalette();
closeAllPalettes();
}

let newNodes = applyNodeChanges(transformedNodeChanges, oldNodes);
Expand Down Expand Up @@ -228,9 +236,14 @@ export const DiagramRenderer = ({ diagramRefreshedEventPayload }: DiagramRendere

const { backgroundColor, smallGridColor, largeGridColor } = diagramBackgroundStyle;

const handleMove: OnMove = useCallback(() => {
const closeAllPalettes = () => {
hideDiagramPalette();
hideDiagramElementPalette();
hideGroupPalette();
};

const handleMove: OnMove = useCallback(() => {
closeAllPalettes();
}, [isDiagramElementPaletteOpened, isDiagramPaletteOpened]);

const handleNodeDragStop: NodeDragHandler = onNodeDragStop((node: Node) => {
Expand All @@ -243,6 +256,18 @@ export const DiagramRenderer = ({ diagramRefreshedEventPayload }: DiagramRendere
onNodesChange([resetPosition]);
});

const handleDiagramElementCLick = (event: React.MouseEvent<Element, MouseEvent>) => {
onDiagramElementClick(event);
onDiagramGroupElementClick(event);
};

const handleSelectionStart = () => {
closeAllPalettes();
};
const handleSelectionEnd = (event: React.MouseEvent<Element, MouseEvent>) => {
onDiagramGroupElementClick(event);
};

const { onNodeMouseEnter, onNodeMouseLeave } = useNodeHover();

return (
Expand All @@ -261,8 +286,8 @@ export const DiagramRenderer = ({ diagramRefreshedEventPayload }: DiagramRendere
onEdgesChange={handleEdgesChange}
onEdgeUpdate={reconnectEdge}
onPaneClick={handlePaneClick}
onEdgeClick={onDiagramElementClick}
onNodeClick={onDiagramElementClick}
onEdgeClick={handleDiagramElementCLick}
onNodeClick={handleDiagramElementCLick}
onMove={handleMove}
nodeDragThreshold={1}
onDrop={onDrop}
Expand All @@ -272,6 +297,8 @@ export const DiagramRenderer = ({ diagramRefreshedEventPayload }: DiagramRendere
onNodeDragStop={handleNodeDragStop}
onNodeMouseEnter={onNodeMouseEnter}
onNodeMouseLeave={onNodeMouseLeave}
onSelectionStart={handleSelectionStart}
onSelectionEnd={handleSelectionEnd}
maxZoom={40}
minZoom={0.1}
snapToGrid={snapToGrid}
Expand Down Expand Up @@ -308,6 +335,12 @@ export const DiagramRenderer = ({ diagramRefreshedEventPayload }: DiagramRendere
refreshEventPayloadId={diagramRefreshedEventPayload.id}
/>

<GroupPalette
refreshEventPayloadId={diagramRefreshedEventPayload.id}
x={groupPalettePosition?.x}
y={groupPalettePosition?.y}
isOpened={isGroupPaletteOpened}
/>
<DiagramPalette diagramElementId={diagramRefreshedEventPayload.diagram.id} />
{diagramDescription.debug ? <DebugPanel reactFlowWrapper={ref} /> : null}
<ConnectorContextualMenu />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*******************************************************************************
* Copyright (c) 2024 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/

import { Paper } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';
import IconButton from '@material-ui/core/IconButton';
import Tooltip from '@material-ui/core/Tooltip';
import TonalityIcon from '@material-ui/icons/Tonality';
import VisibilityOffIcon from '@material-ui/icons/VisibilityOff';
import { memo, useCallback, useState } from 'react';
import { useOnSelectionChange } from 'reactflow';
import { GroupPaletteProps } from './GroupPalette.types';
import { ContextualPaletteStyleProps } from '../Palette.types';
import { PalettePortal } from '../PalettePortal';
import { useHideDiagramElements } from '../../hide/useHideDiagramElements';
import { useDiagramElementPalette } from '../useDiagramElementPalette';
import { useFadeDiagramElements } from '../../fade/useFadeDiagramElements';
import { PinIcon } from '../../../icons/PinIcon';
import { usePinDiagramElements } from '../../pin/usePinDiagramElements';

const usePaletteStyle = makeStyles((theme) => ({
palette: {
border: `1px solid ${theme.palette.divider}`,
borderRadius: '2px',
zIndex: 2,
position: 'fixed',
display: 'flex',
alignItems: 'center',
},
paletteContent: {
display: 'grid',
gridTemplateColumns: ({ toolCount }: ContextualPaletteStyleProps) => `repeat(${Math.min(toolCount, 10)}, 36px)`,
gridTemplateRows: '28px',
gridAutoRows: '28px',
placeItems: 'center',
},
toolIcon: {
color: theme.palette.text.primary,
},
}));

export const GroupPalette = memo(({ x, y, isOpened }: GroupPaletteProps) => {
const { hideDiagramElements } = useHideDiagramElements();
const { fadeDiagramElements } = useFadeDiagramElements();
const { pinDiagramElements } = usePinDiagramElements();
const { hideDiagramElementPalette } = useDiagramElementPalette();
const [selectedElementIds, setSelectedElementIds] = useState<string[]>([]);

const onChange = useCallback(({ nodes }) => {
if (nodes.filter((node) => node.selected).length > 1) {
setSelectedElementIds(nodes.filter((node) => node.selected).map((node) => node.id));
} else {
setSelectedElementIds([]);
}
}, []);
useOnSelectionChange({
onChange,
});

const toolCount = 3;
const classes = usePaletteStyle({ toolCount });

const shouldRender = selectedElementIds.length > 1 && isOpened && x && y;
if (!shouldRender) {
return null;
}
hideDiagramElementPalette();

return (
<PalettePortal>
<Paper className={classes.palette} style={{ position: 'absolute', left: x, top: y }} data-testid="GroupPalette">
<div className={classes.paletteContent}>
<Tooltip title="Hide elements">
<IconButton
className={classes.toolIcon}
size="small"
aria-label="hide elements"
onClick={() => hideDiagramElements(selectedElementIds, true)}
data-testid="Hide-elements">
<VisibilityOffIcon fontSize="small" />
</IconButton>
</Tooltip>
<Tooltip title="Fade elements">
<IconButton
className={classes.toolIcon}
size="small"
aria-label="Fade elements"
onClick={() => fadeDiagramElements(selectedElementIds, true)}
data-testid="Fade-elements">
<TonalityIcon fontSize="small" />
</IconButton>
</Tooltip>
<Tooltip title="Pin element">
<IconButton
className={classes.toolIcon}
size="small"
aria-label="Pin element"
onClick={() => pinDiagramElements(selectedElementIds, true)}
data-testid="Pin-element">
<PinIcon fontSize="small" />
</IconButton>
</Tooltip>
</div>
</Paper>
</PalettePortal>
);
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*******************************************************************************
* Copyright (c) 2024 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/

export interface GroupPaletteProps {
x?: number;
y?: number;
isOpened: boolean;
refreshEventPayloadId: string;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*******************************************************************************
* Copyright (c) 2024 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/
import { useCallback, useState } from 'react';
import { XYPosition, useStoreApi } from 'reactflow';
import { UseGroupPaletteValue, UseGroupPaletteState } from './useGroupPalette.types';

const computePalettePosition = (event: MouseEvent | React.MouseEvent, bounds?: DOMRect): XYPosition => {
return {
x: event.clientX - (bounds?.left ?? 0),
y: event.clientY - (bounds?.top ?? 0),
};
};

export const useGroupPalette = (): UseGroupPaletteValue => {
const [state, setState] = useState<UseGroupPaletteState>({ position: null, isOpened: false });

const store = useStoreApi();

const onDiagramGroupElementClick = useCallback((event: React.MouseEvent<Element, MouseEvent>) => {
const { domNode } = store.getState();
const element = domNode?.getBoundingClientRect();
const palettePosition = computePalettePosition(event, element);
setState((prevState) => ({ ...prevState, position: palettePosition, isOpened: true }));
}, []);

const hideGroupPalette = () => {
setState((prevState) => ({ ...prevState, position: null, isOpened: false }));
};
return {
position: state.position,
isOpened: state.isOpened,
hideGroupPalette,
onDiagramGroupElementClick,
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*******************************************************************************
* Copyright (c) 2024 Obeo.
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Obeo - initial API and implementation
*******************************************************************************/

import { XYPosition } from 'reactflow';

export interface UseGroupPaletteValue {
position: XYPosition | null;
isOpened: boolean;
hideGroupPalette: () => void;
onDiagramGroupElementClick: (event: React.MouseEvent<Element, MouseEvent>) => void;
}

export interface UseGroupPaletteState {
position: XYPosition | null;
isOpened: boolean;
}

0 comments on commit e9eff1d

Please sign in to comment.