diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java index 0898eeb37e..662373d945 100644 --- a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphDisplay.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -1195,6 +1195,11 @@ public class DefaultGraphDisplay implements GraphDisplay { : MultiSelectionStrategy.rectangular()) .viewSize(PREFERRED_VIEW_SIZE) .layoutSize(PREFERRED_LAYOUT_SIZE) + +// // This is a reminder of how we can change the modifier keys for graph scaling +// .graphMouse(DefaultGraphMouse.builder() +// .yAxisScalingMask(Modifiers.masks.get("SHIFT_MENU")) +// .build()) .build(); // Add an ancestor listener to scale and center the graph after the component diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphRenderer.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphRenderer.java index e1e76721a7..cd8efbc4dd 100644 --- a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphRenderer.java +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/DefaultGraphRenderer.java @@ -120,6 +120,7 @@ public class DefaultGraphRenderer implements GraphRenderer { s -> RectangleUtils.convert(s.getBounds2D()); if (options.usesIcons()) { + // set up the shape and color functions IconShapeFunction nodeShaper = new IconShapeFunction<>(new EllipseShapeFunction<>()); diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutFunction.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutFunction.java index d8103afe3f..334ecb31cc 100644 --- a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutFunction.java +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutFunction.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -27,6 +27,7 @@ import org.jungrapht.visualization.layout.algorithms.sugiyama.Layering; import com.google.common.base.Objects; +import ghidra.graph.visualization.layout.JgtTidierTreeLayoutAlgorithm; import ghidra.service.graph.AttributedEdge; import ghidra.service.graph.AttributedVertex; @@ -49,11 +50,9 @@ class LayoutFunction edge -> Objects.equal(edge.getEdgeType(), renderer.getFavoredEdgeType()); } - - @Override public LayoutAlgorithm.Builder apply(String name) { - switch(name) { + switch (name) { case GEM: return GEMLayoutAlgorithm.edgeAwareBuilder(); case FORCED_BALANCED: @@ -61,10 +60,10 @@ class LayoutFunction .preRelaxDuration(1000); case FORCE_DIRECTED: return FRLayoutAlgorithm. builder() - .repulsionContractBuilder(BarnesHutFRRepulsion.builder()); + .repulsionContractBuilder(BarnesHutFRRepulsion.builder()); case CIRCLE: return CircleLayoutAlgorithm. builder() - .reduceEdgeCrossing(false); + .reduceEdgeCrossing(false); case COMPACT_RADIAL: return TidierRadialTreeLayoutAlgorithm . edgeAwareBuilder() @@ -116,20 +115,19 @@ class LayoutFunction case RADIAL: return RadialTreeLayoutAlgorithm . builder() - .verticalVertexSpacing(300); + .verticalVertexSpacing(300); case BALLOON: return BalloonLayoutAlgorithm . builder() .verticalVertexSpacing(300); case HIERACHICAL: return EdgeAwareTreeLayoutAlgorithm - .edgeAwareBuilder(); + . edgeAwareBuilder(); case COMPACT_HIERARCHICAL: default: - return TidierTreeLayoutAlgorithm - . edgeAwareBuilder() + return JgtTidierTreeLayoutAlgorithm + .edgeAwareBuilder() .edgeComparator(edgeTypeComparator); - } } } diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutTransitionManager.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutTransitionManager.java index 163b5abab1..c4f299ceda 100644 --- a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutTransitionManager.java +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/LayoutTransitionManager.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -89,6 +89,7 @@ class LayoutTransitionManager { ((VertexBoundsFunctionConsumer) layoutAlgorithm) .setVertexBoundsFunction(vertexBoundsFunction); } + // mincross layouts are 'layered'. put some bounds on the number of // iterations of the level cross function based on the size of the graph // very large graphs do not improve enough to out-weigh the cost of @@ -97,13 +98,14 @@ class LayoutTransitionManager { ((Layered) layoutAlgorithm).setMaxLevelCrossFunction( g -> Math.max(1, Math.min(10, 500 / g.vertexSet().size()))); } - // tree layouts need a way to determine which vertices are roots - // especially when the graph is not a DAG + + // tree layouts need a way to determine which vertices are roots, especially when the graph + // is not a DAG if (layoutAlgorithm instanceof TreeLayout) { ((TreeLayout) layoutAlgorithm).setRootPredicate(rootPredicate); } - // remove any previously added layout paintables - // and apply paintables to these 2 algorithms + + // remove any previously added layout paintables and apply paintables to these 2 algorithms removePaintable(radialLayoutRings); removePaintable(balloonLayoutRings); if (layoutAlgorithm instanceof BalloonLayoutAlgorithm) { diff --git a/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/layout/JgtTidierTreeLayoutAlgorithm.java b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/layout/JgtTidierTreeLayoutAlgorithm.java new file mode 100644 index 0000000000..7ae8584e46 --- /dev/null +++ b/Ghidra/Features/GraphServices/src/main/java/ghidra/graph/visualization/layout/JgtTidierTreeLayoutAlgorithm.java @@ -0,0 +1,69 @@ +/* ### + * IP: GHIDRA + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ghidra.graph.visualization.layout; + +import java.util.function.Function; + +import org.jgrapht.Graph; +import org.jungrapht.visualization.layout.algorithms.TidierTreeLayoutAlgorithm; +import org.jungrapht.visualization.layout.model.Dimension; +import org.jungrapht.visualization.layout.model.Rectangle; + +import ghidra.service.graph.AttributedEdge; +import ghidra.service.graph.AttributedVertex; + +/** + * Overridden to fix spacing issues on the vertical and horizontal axes. + */ +public class JgtTidierTreeLayoutAlgorithm + extends TidierTreeLayoutAlgorithm { + + @SuppressWarnings("unchecked") + public static Builder edgeAwareBuilder() { + return new Builder<>(); + } + + public JgtTidierTreeLayoutAlgorithm(Builder builder) { + super(builder); + + // when true, excess vertical space sometimes appears that users don't like + expandLayout = false; + } + + @Override + protected Dimension computeAverageVertexDimension(Graph graph, + Function shapeFunction) { + + // The super call uses the average size of the vertices to create spacing. Large vertices + // can cause a large amount of space to be used on the x axis. + return Dimension.of(50, 50); + } + + //@formatter:off + public static class Builder< + T extends TidierTreeLayoutAlgorithm, + B extends Builder> + + extends TidierTreeLayoutAlgorithm.Builder { + + @SuppressWarnings("unchecked") + @Override + public T build() { + return (T) new JgtTidierTreeLayoutAlgorithm(this); + } + } + //@formatter:on +}