Merge remote-tracking branch 'origin/GT-3020-dragonmacher-fg-edges-lose-alpha'

This commit is contained in:
Ryan Kurtz 2019-08-12 12:17:38 -04:00
commit e36b22d268
23 changed files with 581 additions and 282 deletions

View file

@ -19,6 +19,16 @@ import ghidra.app.plugin.core.functiongraph.graph.vertex.FGVertex;
import ghidra.graph.viewer.VisualEdge;
import ghidra.program.model.symbol.FlowType;
/**
* This version of the {@link VisualEdge} adds a few methods.
*
* <p>The {@link #setDefaultAlpha(double)} method was added here instead of the base interface, as it
* was not needed any higher at the time of writing. It can be pulled-up, but there is most
* likely a better pattern for specifying visual attributes of an edge. If we find we need more
* methods like this, then that is a good time for a refactor to change how we manipulate
* rending attributes from various parts of the API (e.g., from the layouts and from animation
* jobs).
*/
public interface FGEdge extends VisualEdge<FGVertex> {
public FlowType getFlowType();
@ -27,6 +37,30 @@ public interface FGEdge extends VisualEdge<FGVertex> {
public void setLabel(String label);
/**
* Set this edge's base alpha, which determines how much of the edge is visible/see through.
* 0 is completely transparent.
*
* <P>This differs from {@link #setAlpha(double)} in that the latter is used for
* temporary display effects. This method is used to set the alpha value for the edge when
* it is not part of a temporary display effect.
*
* @param alpha the alpha value
*/
public void setDefaultAlpha(double alpha);
/**
* Set this edge's base alpha, which determines how much of the edge is visible/see through.
* 0 is completely transparent.
*
* <P>This differs from {@link #getAlpha()} in that the latter is used for
* temporary display effects. This method is used to set the alpha value for the edge when
* it is not part of a temporary display effect.
*
* @return the alpha value
*/
public double getDefaultAlpha();
@SuppressWarnings("unchecked")
// Suppressing warning on the return type; we know our class is the right type
@Override

View file

@ -34,10 +34,12 @@ public class FGEdgeImpl implements FGEdge {
boolean doHashCode = true;
int hashCode;
private boolean inActivePath = false;
private boolean inHoveredPath = false;
private boolean inFocusedPath = false;
private boolean selected = false;
private double emphasis = 0D;
private double alpha = 1D;
private double defaultAlpha = 1D;
private double alpha = defaultAlpha;
private String edgeLabel = null;
public FGEdgeImpl(FGVertex startVertex, FGVertex destinationVertex, FlowType flowType,
@ -50,13 +52,23 @@ public class FGEdgeImpl implements FGEdge {
}
@Override
public boolean isInActivePath() {
return inActivePath;
public boolean isInHoveredVertexPath() {
return inHoveredPath;
}
@Override
public void setInActivePath(boolean inActivePath) {
this.inActivePath = inActivePath;
public boolean isInFocusedVertexPath() {
return inFocusedPath;
}
@Override
public void setInHoveredVertexPath(boolean inPath) {
this.inHoveredPath = inPath;
}
@Override
public void setInFocusedVertexPath(boolean inPath) {
this.inFocusedPath = inPath;
}
@Override
@ -89,6 +101,17 @@ public class FGEdgeImpl implements FGEdge {
return alpha;
}
@Override
public void setDefaultAlpha(double alpha) {
this.defaultAlpha = alpha;
this.alpha = alpha;
}
@Override
public double getDefaultAlpha() {
return defaultAlpha;
}
@Override
public List<Point2D> getArticulationPoints() {
return layoutArticulationPoints;
@ -135,7 +158,9 @@ public class FGEdgeImpl implements FGEdge {
newEdge.layoutArticulationPoints = newPoints;
newEdge.alpha = alpha;
newEdge.inActivePath = inActivePath;
newEdge.defaultAlpha = defaultAlpha;
newEdge.inHoveredPath = inHoveredPath;
newEdge.inFocusedPath = inFocusedPath;
newEdge.selected = selected;
return newEdge;
}

View file

@ -68,7 +68,7 @@ public abstract class AbstractGroupingFunctionGraphJob extends AbstractFunctionG
*/
AbstractGroupingFunctionGraphJob(FGController controller,
GroupedFunctionGraphVertex groupVertex, Set<FGVertex> newVertices,
Set<FGVertex> verticesToRemove, boolean relayloutOverride, boolean useAnimation) {
Set<FGVertex> verticesToRemove, boolean relayoutOverride, boolean useAnimation) {
super(controller, useAnimation);
@ -87,7 +87,7 @@ public abstract class AbstractGroupingFunctionGraphJob extends AbstractFunctionG
FunctionGraphOptions options = controller.getFunctionGraphOptions();
RelayoutOption relayoutOption = options.getRelayoutOption();
this.relayout = relayoutOption == VERTEX_GROUPING_CHANGES || relayoutOption == ALWAYS ||
relayloutOverride;
relayoutOverride;
}
@Override
@ -158,7 +158,7 @@ public abstract class AbstractGroupingFunctionGraphJob extends AbstractFunctionG
return positions;
}
/**
/*
* Subclasses must return locations for vertices. This method will be called when no
* relayout will be performed.
*
@ -191,15 +191,21 @@ public abstract class AbstractGroupingFunctionGraphJob extends AbstractFunctionG
@Override
protected void updateOpacity(double percentComplete) {
double oldComponentsAlpha = 1.0 - percentComplete;
Collection<FGVertex> vertices = getVerticesToBeRemoved();
for (FGVertex vertex : vertices) {
vertex.setAlpha(oldComponentsAlpha);
Collection<FGEdge> edges = getEdges(vertex);
for (FGEdge edge : edges) {
edge.setAlpha(oldComponentsAlpha);
// don't go past the alpha when removing
double defaultAlpha = edge.getDefaultAlpha();
double alpha = Math.min(oldComponentsAlpha, defaultAlpha);
edge.setAlpha(alpha);
}
}
@ -210,7 +216,11 @@ public abstract class AbstractGroupingFunctionGraphJob extends AbstractFunctionG
Collection<FGEdge> edges = getEdges(vertex);
for (FGEdge edge : edges) {
edge.setAlpha(newComponentsAlpha);
// don't go past the alpha when adding
double defaultAlpha = edge.getDefaultAlpha();
double alpha = Math.min(newComponentsAlpha, defaultAlpha);
edge.setAlpha(alpha);
}
}
}

View file

@ -19,6 +19,7 @@ import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.util.*;
import org.apache.commons.collections4.IterableUtils;
import org.jdesktop.animation.timing.Animator;
import org.jdesktop.animation.timing.interpolation.PropertySetter;
@ -197,22 +198,25 @@ public class MergeVertexFunctionGraphJob extends AbstractAnimatorJob {
parentVertex.setAlpha(oldComponentsAlpha);
childVertex.setAlpha(oldComponentsAlpha);
Collection<FGEdge> edges = getEdges(parentVertex);
Iterable<FGEdge> edges =
IterableUtils.chainedIterable(getEdges(parentVertex), getEdges(childVertex));
for (FGEdge edge : edges) {
edge.setAlpha(oldComponentsAlpha);
}
edges = getEdges(childVertex);
for (FGEdge edge : edges) {
edge.setAlpha(oldComponentsAlpha);
// don't go past the alpha when removing
double defaultAlpha = edge.getDefaultAlpha();
double alpha = Math.min(oldComponentsAlpha, defaultAlpha);
edge.setAlpha(alpha);
}
double newComponentsAlpha = percentComplete;
mergedVertex.setAlpha(newComponentsAlpha);
edges = getEdges(mergedVertex);
for (FGEdge edge : edges) {
edge.setAlpha(newComponentsAlpha);
// don't go past the alpha when adding
double defaultAlpha = edge.getDefaultAlpha();
double alpha = Math.min(newComponentsAlpha, defaultAlpha);
edge.setAlpha(alpha);
}
}

View file

@ -19,6 +19,7 @@ import java.awt.Rectangle;
import java.awt.geom.Point2D;
import java.util.*;
import org.apache.commons.collections4.IterableUtils;
import org.jdesktop.animation.timing.Animator;
import org.jdesktop.animation.timing.interpolation.PropertySetter;
@ -114,9 +115,21 @@ public class SplitVertexFunctionGraphJob extends AbstractAnimatorJob {
controller.synchronizeProgramLocationAfterEdit();
restoreEdgeDisplayAttributes();
viewer.repaint();
}
private void restoreEdgeDisplayAttributes() {
Iterable<FGEdge> edges =
IterableUtils.chainedIterable(getEdges(parentVertex), getEdges(childVertex));
for (FGEdge edge : edges) {
double alpha = edge.getDefaultAlpha();
edge.setAlpha(alpha);
}
}
public void setPercentComplete(double percentComplete) {
trace("setPercentComplete() callback: " + percentComplete);
updateNewVertexPositions(percentComplete);
@ -214,7 +227,11 @@ public class SplitVertexFunctionGraphJob extends AbstractAnimatorJob {
Collection<FGEdge> edges = getEdges(toSplitVertex);
for (FGEdge edge : edges) {
edge.setAlpha(oldComponentsAlpha);
// don't go past the alpha when removing
double defaultAlpha = edge.getDefaultAlpha();
double alpha = Math.min(oldComponentsAlpha, defaultAlpha);
edge.setAlpha(alpha);
}
double newComponentsAlpha = percentComplete;
@ -223,12 +240,19 @@ public class SplitVertexFunctionGraphJob extends AbstractAnimatorJob {
edges = getEdges(parentVertex);
for (FGEdge edge : edges) {
edge.setAlpha(newComponentsAlpha);
// don't go past the alpha when adding
double defaultAlpha = edge.getDefaultAlpha();
double alpha = Math.min(newComponentsAlpha, defaultAlpha);
edge.setAlpha(alpha);
}
edges = getEdges(childVertex);
for (FGEdge edge : edges) {
edge.setAlpha(newComponentsAlpha);
// don't go past the alpha when adding
double defaultAlpha = edge.getDefaultAlpha();
double alpha = Math.min(newComponentsAlpha, defaultAlpha);
edge.setAlpha(alpha);
}
}

View file

@ -21,6 +21,7 @@ import java.awt.Color;
import java.awt.geom.Point2D;
import java.util.*;
import org.apache.commons.collections4.IterableUtils;
import org.junit.*;
import docking.ActionContext;
@ -37,6 +38,7 @@ import ghidra.framework.plugintool.util.PluginException;
import ghidra.graph.viewer.options.RelayoutOption;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import util.CollectionUtils;
public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
@ -809,14 +811,41 @@ public class FunctionGraphGroupVertices1Test extends AbstractFunctionGraphTest {
verifyDefaultColor(v2);
}
@Test
public void testEdgeDefaultAlphaPersistsAfterGrouping() {
graphFunction("01002cf5");
FGVertex v1 = vertex("01002cf5");
FGVertex v2 = vertex("01002d0f");
FunctionGraph graph = getFunctionGraph();
Iterable<FGEdge> edges = graph.getEdges(v1, v2);
assertEquals(1, IterableUtils.size(edges));
FGEdge edge = CollectionUtils.any(edges);
Double alpha = edge.getAlpha();
assertTrue(alpha < 1.0); // this is the default flow
GroupedFunctionGraphVertex group = group("A", v1, v2);
ungroup(group);
edges = graph.getEdges(v1, v2);
assertEquals(1, IterableUtils.size(edges));
edge = CollectionUtils.any(edges);
Double alphAfterGroup = edge.getAlpha();
assertEquals(alpha, alphAfterGroup);
}
@Test
public void testSymbolAddedWhenGrouped_SymbolOutsideOfGroupNode() {
// TODO
}
//==================================================================================================
// Private Methods
//==================================================================================================
//==================================================================================================
// Private Methods
//==================================================================================================
// @formatter:off
@Override

View file

@ -313,7 +313,7 @@ public class TestFGLayoutProvider extends FGLayoutProvider {
}
else if (startCol.index > endCol.index) { // flow return
e.setAlpha(.25);
e.setDefaultAlpha(.25);
Shape shape = transformer.apply(startVertex);
Rectangle bounds = shape.getBounds();
@ -338,7 +338,7 @@ public class TestFGLayoutProvider extends FGLayoutProvider {
else { // same column--nothing to route
// straight line, which is the default
e.setAlpha(.25);
e.setDefaultAlpha(.25);
}
newEdgeArticulations.put(e, articulations);
}