Merge remote-tracking branch 'origin/GP-4741-dragonmacher-graph-size-fix--SQUASHED'

This commit is contained in:
Ryan Kurtz
2025-07-08 06:05:22 -04:00
5 changed files with 95 additions and 20 deletions

View File

@@ -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

View File

@@ -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<AttributedVertex> nodeShaper =
new IconShapeFunction<>(new EllipseShapeFunction<>());

View File

@@ -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<AttributedVertex, ?, ?> 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.<AttributedVertex> builder()
.repulsionContractBuilder(BarnesHutFRRepulsion.builder());
.repulsionContractBuilder(BarnesHutFRRepulsion.builder());
case CIRCLE:
return CircleLayoutAlgorithm.<AttributedVertex> builder()
.reduceEdgeCrossing(false);
.reduceEdgeCrossing(false);
case COMPACT_RADIAL:
return TidierRadialTreeLayoutAlgorithm
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
@@ -116,20 +115,19 @@ class LayoutFunction
case RADIAL:
return RadialTreeLayoutAlgorithm
.<AttributedVertex> builder()
.verticalVertexSpacing(300);
.verticalVertexSpacing(300);
case BALLOON:
return BalloonLayoutAlgorithm
.<AttributedVertex> builder()
.verticalVertexSpacing(300);
case HIERACHICAL:
return EdgeAwareTreeLayoutAlgorithm
.<AttributedVertex, AttributedEdge>edgeAwareBuilder();
.<AttributedVertex, AttributedEdge> edgeAwareBuilder();
case COMPACT_HIERARCHICAL:
default:
return TidierTreeLayoutAlgorithm
.<AttributedVertex, AttributedEdge> edgeAwareBuilder()
return JgtTidierTreeLayoutAlgorithm
.edgeAwareBuilder()
.edgeComparator(edgeTypeComparator);
}
}
}

View File

@@ -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<AttributedVertex>) 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<AttributedVertex, AttributedEdge>) 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<AttributedVertex>) 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) {

View File

@@ -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<AttributedVertex, AttributedEdge> {
@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 <E> Dimension computeAverageVertexDimension(Graph<AttributedVertex, E> graph,
Function<AttributedVertex, Rectangle> 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<AttributedVertex, AttributedEdge>,
B extends Builder<T, B>>
extends TidierTreeLayoutAlgorithm.Builder<AttributedVertex, AttributedEdge, T, B> {
@SuppressWarnings("unchecked")
@Override
public T build() {
return (T) new JgtTidierTreeLayoutAlgorithm(this);
}
}
//@formatter:on
}