Skip to content

Commit

Permalink
[2883] Store in node layout data if a user has resized the node
Browse files Browse the repository at this point in the history
Bug: #2883
Signed-off-by: Guillaume Coutable <guillaume.coutable@obeo.fr>
  • Loading branch information
gcoutable committed Jan 8, 2024
1 parent e9c04b9 commit 86f0c9d
Show file tree
Hide file tree
Showing 24 changed files with 144 additions and 42 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ const nodeTypeRegistry: NodeTypeRegistry = {
</SiriusWebApplication>
```
- https://github.com/eclipse-sirius/sirius-web/issues/2790[#2790] [diagram] All handles used to resize a node have been updated to be wider, you can update your custom nodes in the same way it's done in the EllipseNode example.
- https://github.com/eclipse-sirius/sirius-web/issues/2883[#2883] [diagram] Add the attribute `resizedByUser` to reactflow nodes and graphql nodes.


=== Dependency update
Expand All @@ -88,6 +89,7 @@ const nodeTypeRegistry: NodeTypeRegistry = {
- https://github.com/eclipse-sirius/sirius-web/issues/2826[#2826] [diagram] Fix invalid reference position used for nodes with a depth superior to 2.

=== New Features

- https://github.com/eclipse-sirius/sirius-web/issues/2413[#2413] Add a debug mode for React Flow diagrams

- https://github.com/eclipse-sirius/sirius-web/issues/2735[#2735] [gantt] Contribute the first version of the Gantt representation.
Expand All @@ -96,6 +98,9 @@ const nodeTypeRegistry: NodeTypeRegistry = {
- https://github.com/eclipse-sirius/sirius-web/issues/2736[#2736] [gantt] Add a starter project for beans related to task meta-model.
- https://github.com/eclipse-sirius/sirius-web/issues/2819[#2819] [deck] Contribute the first version of the Deck representation.
- https://github.com/eclipse-sirius/sirius-web/issues/2765[#2765] [portal] Contribute the first version of the Portal representation.
- https://github.com/eclipse-sirius/sirius-web/issues/2883[#2883] [diagram] The size of manually resized node does not change anymore, unless it needs to.
+
The size of nodes that do not have been resized manually tries to fit the node default size.

=== Improvements

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2019, 2023 Obeo.
* Copyright (c) 2019, 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
Expand Down Expand Up @@ -132,7 +132,7 @@ public void handle(One<IPayload> payloadSink, Many<ChangeDescription> changeDesc
var nodeLayoutData = layoutDiagramInput.diagramLayoutData().nodeLayoutData().stream()
.collect(Collectors.toMap(
NodeLayoutDataInput::id,
nodeLayoutDataInput -> new NodeLayoutData(nodeLayoutDataInput.id(), nodeLayoutDataInput.position(), nodeLayoutDataInput.size())
nodeLayoutDataInput -> new NodeLayoutData(nodeLayoutDataInput.id(), nodeLayoutDataInput.position(), nodeLayoutDataInput.size(), nodeLayoutDataInput.resizedByUser())
));

var layoutData = new DiagramLayoutData(nodeLayoutData, Map.of(), Map.of());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2023 Obeo.
* Copyright (c) 2023, 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
Expand All @@ -20,5 +20,5 @@
*
* @author sbegaudeau
*/
public record NodeLayoutDataInput(String id, Position position, Size size) {
public record NodeLayoutDataInput(String id, Position position, Size size, boolean resizedByUser) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ type NodeLayoutData {
id: ID!
position: Position!
size: Size!
resizedByUser: Boolean!
}

enum ViewModifier {
Expand Down Expand Up @@ -77,6 +78,7 @@ type Node {
defaultWidth: Int
defaultHeight: Int
labelEditable: Boolean!
resizedByUser: Boolean!
}

type FreeFormLayoutStrategy {
Expand Down Expand Up @@ -590,6 +592,7 @@ input NodeLayoutDataInput {
id: ID!
position: PositionInput!
size: SizeInput!
resizedByUser: Boolean!
}

input SizeInput {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*******************************************************************************
* 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
*******************************************************************************/

package org.eclipse.sirius.components.diagrams.graphql.datafetchers.diagram;

import java.util.Map;
import java.util.Optional;

import org.eclipse.sirius.components.annotations.spring.graphql.QueryDataFetcher;
import org.eclipse.sirius.components.diagrams.Diagram;
import org.eclipse.sirius.components.diagrams.Node;
import org.eclipse.sirius.components.diagrams.layoutdata.DiagramLayoutData;
import org.eclipse.sirius.components.diagrams.layoutdata.NodeLayoutData;
import org.eclipse.sirius.components.graphql.api.IDataFetcherWithFieldCoordinates;

import graphql.schema.DataFetchingEnvironment;

/**
* Used to retrieve the resized by user from diagram layout data.
*
* @author gcoutable
*/
@QueryDataFetcher(type = "Node", field = "resizedByUser")
public class NodeResizedByUserDataFetcher implements IDataFetcherWithFieldCoordinates<Boolean> {

@Override
public Boolean get(DataFetchingEnvironment environment) throws Exception {
Node node = environment.getSource();
Map<String, Object> localContext = environment.getLocalContext();

return Optional.ofNullable(localContext.get("diagram"))
.filter(Diagram.class::isInstance)
.map(Diagram.class::cast)
.flatMap(diagram -> this.resizedByUser(diagram, node))
.orElse(false);
}

private Optional<Boolean> resizedByUser(Diagram diagram, Node node) {
return Optional.of(diagram.getLayoutData())
.map(DiagramLayoutData::nodeLayoutData)
.map(layoutData -> layoutData.get(node.getId()))
.map(NodeLayoutData::resizedByUser);
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2023 Obeo.
* Copyright (c) 2023, 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
Expand Down Expand Up @@ -67,7 +67,7 @@ public DiagramLayoutData layout(DiagramLayoutConfiguration diagramLayoutConfigur
}

Map<String, NodeLayoutData> newNodeLayoutData = new HashMap<>();
diagramBoxModel.nodeBoxModels().forEach((nodeId, nodeBoxModel) -> newNodeLayoutData.put(nodeId, new NodeLayoutData(nodeId, nodeBoxModel.bounds().topLeft(), nodeBoxModel.bounds().size())));
diagramBoxModel.nodeBoxModels().forEach((nodeId, nodeBoxModel) -> newNodeLayoutData.put(nodeId, new NodeLayoutData(nodeId, nodeBoxModel.bounds().topLeft(), nodeBoxModel.bounds().size(), false)));

return new DiagramLayoutData(newNodeLayoutData, Map.of(), Map.of());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2023 Obeo.
* Copyright (c) 2023, 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
Expand All @@ -20,6 +20,7 @@
public record NodeLayoutData(
String id,
Position position,
Size size
Size size,
boolean resizedByUser
) {
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ const toIconLabelNode = (
state,
style,
labelEditable,
resizedByUser,
} = gqlNode;

const connectionHandles: ConnectionHandle[] = [];
Expand All @@ -71,6 +72,7 @@ const toIconLabelNode = (
labelEditable: labelEditable,
connectionHandles,
isNew,
resizedByUser,
};

if (insideLabel) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const toImageNode = (
state,
style,
labelEditable,
resizedByUser,
} = gqlNode;

const connectionHandles: ConnectionHandle[] = convertHandles(gqlNode, gqlEdges);
Expand All @@ -68,6 +69,7 @@ const toImageNode = (
positionDependentRotation: style.positionDependentRotation,
connectionHandles,
isNew,
resizedByUser,
};

if (insideLabel) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ const toListNode = (
state,
style,
labelEditable,
resizedByUser,
} = gqlNode;

const connectionHandles: ConnectionHandle[] = convertHandles(gqlNode, gqlEdges);
Expand Down Expand Up @@ -91,6 +92,7 @@ const toListNode = (
areChildNodesDraggable: isListLayoutStrategy(gqlNode.childrenLayoutStrategy)
? gqlNode.childrenLayoutStrategy.areChildNodesDraggable
: true,
resizedByUser,
};

if (insideLabel) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const toRectangularNode = (
state,
style,
labelEditable,
resizedByUser,
} = gqlNode;

const connectionHandles: ConnectionHandle[] = convertHandles(gqlNode, gqlEdges);
Expand Down Expand Up @@ -79,6 +80,7 @@ const toRectangularNode = (
labelEditable,
connectionHandles,
isNew,
resizedByUser,
};

if (insideLabel) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,6 @@ fragment nodeFragment on Node {
defaultWidth
defaultHeight
labelEditable
resizedByUser
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export interface GQLNode<T extends GQLNodeStyle> {
defaultWidth: number | null;
defaultHeight: number | null;
labelEditable: boolean;
resizedByUser: boolean;
}

export interface ILayoutStrategy {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export interface NodeData {
style: React.CSSProperties;
connectionHandles: ConnectionHandle[];
isNew: boolean;
resizedByUser: boolean;
}

export enum BorderNodePosition {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2023 Obeo.
* Copyright (c) 2023, 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
Expand All @@ -11,7 +11,7 @@
* Obeo - initial API and implementation
*******************************************************************************/

import { Node, NodeChange, useReactFlow } from 'reactflow';
import { Node, NodeChange, NodeDimensionChange, NodePositionChange, useReactFlow } from 'reactflow';
import { EdgeData, NodeData } from '../DiagramRenderer.types';
import { useDropNode } from '../dropNode/useDropNode';
import { RawDiagram } from '../layout/layout.types';
Expand All @@ -26,31 +26,51 @@ export const useLayoutOnBoundsChange = (refreshEventPayloadId: string): UseLayou
const { hasDroppedNodeParentChanged } = useDropNode();
const { synchronizeLayoutData } = useSynchronizeLayoutData();

const isMoveFinished = (change: NodeChange): boolean => {
const isMoveFinished = (change: NodeChange): change is NodePositionChange => {
return (
change.type === 'position' &&
typeof change.dragging === 'boolean' &&
!change.dragging &&
!hasDroppedNodeParentChanged()
);
};
const isResizeFinished = (change: NodeChange): boolean =>
const isResizeFinished = (change: NodeChange): change is NodeDimensionChange =>
change.type === 'dimensions' && typeof change.resizing === 'boolean' && !change.resizing;

const isBoundsChangeFinished = (changes: NodeChange[]): NodeChange | undefined => {
return changes.find((change) => isMoveFinished(change) || isResizeFinished(change));
};

const updateNodeResizeByUserState = (
changes: NodeChange[],
nodes: Node<NodeData, DiagramNodeType>[]
): Node<NodeData, DiagramNodeType>[] => {
return nodes.map((node) => {
if (changes.filter(isResizeFinished).find((dimensionChange) => dimensionChange.id === node.id)) {
return {
...node,
data: {
...node.data,
resizedByUser: true,
},
};
}
return node;
});
};

const layoutOnBoundsChange = (changes: NodeChange[], nodes: Node<NodeData, DiagramNodeType>[]): void => {
const change = isBoundsChangeFinished(changes);
if (change) {
const updatedNodes = updateNodeResizeByUserState(changes, nodes);

const diagramToLayout: RawDiagram = {
nodes,
nodes: updatedNodes,
edges: getEdges(),
};

layout(diagramToLayout, diagramToLayout, null, (laidOutDiagram) => {
nodes.map((node) => {
updatedNodes.map((node) => {
const existingNode = laidOutDiagram.nodes.find((laidoutNode) => laidoutNode.id === node.id);
if (existingNode) {
return {
Expand All @@ -67,10 +87,10 @@ export const useLayoutOnBoundsChange = (refreshEventPayloadId: string): UseLayou
}
return node;
});
setNodes(nodes);
setNodes(updatedNodes);
setEdges(laidOutDiagram.edges);
const finalDiagram: RawDiagram = {
nodes: nodes,
nodes: updatedNodes,
edges: laidOutDiagram.edges,
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2023 Obeo.
* Copyright (c) 2023, 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
Expand Down Expand Up @@ -124,7 +124,7 @@ export class ImageNodeLayoutHandler implements INodeLayoutHandler<ImageNodeData>
const previousNode = (previousDiagram?.nodes ?? []).find((previous) => previous.id === node.id);
const previousDimensions = computePreviousSize(previousNode, node);

if (node.data.nodeDescription?.userResizable) {
if (node.data.resizedByUser) {
if (minNodeWith > previousDimensions.width) {
node.width = minNodeWith;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export class ListNodeLayoutHandler implements INodeLayoutHandler<ListNodeData> {
const previousNode = (previousDiagram?.nodes ?? []).find((previouseNode) => previouseNode.id === node.id);
const previousDimensions = computePreviousSize(previousNode, node);

if (node.data.nodeDescription?.userResizable) {
if (node.data.resizedByUser) {
if (minNodeWith > previousDimensions.width) {
node.width = minNodeWith;
} else {
Expand Down Expand Up @@ -127,7 +127,7 @@ export class ListNodeLayoutHandler implements INodeLayoutHandler<ListNodeData> {

if (!forceWidth) {
let previousChildrenContentBoxWidthToConsider: number = 0;
if (node.data.nodeDescription?.userResizable) {
if (node.data.resizedByUser) {
previousChildrenContentBoxWidthToConsider = (previousNode?.width ?? 0) - borderWidth * 2;
}
const widerWidth = Math.max(
Expand Down Expand Up @@ -173,8 +173,7 @@ export class ListNodeLayoutHandler implements INodeLayoutHandler<ListNodeData> {
node.width = forceWidth ?? getNodeOrMinWidth(nodeWidth, node);

const minNodeheight = getNodeOrMinHeight(nodeHeight, node);
// TODO: rework this.
if (node.data.nodeDescription?.userResizable && previousNode) {
if (node.data.resizedByUser && previousNode) {
if (minNodeheight > (previousNode.height ?? 0)) {
node.height = minNodeheight;
} else {
Expand Down
Loading

0 comments on commit 86f0c9d

Please sign in to comment.