[turbolizer] Features and bug-fixes
Fix bugs and add a few small useful features: * Fix Schedule view to properly parse schedule output and respond to switching back to graph views. * Add shorcuts for showing edges of selected nodes. - 'i' shows all inputs - 'o' shows all outputs - '1'-'9' shows all nodes nth input where 1 <= n <= 9 - 'c' shows all control inputs - 'e' shows all effect inputs * Holding the control key down when using a edge-showing shortcut toggles edge state rather the just showing. * 'a' selects all nodes in graph view. * Node selection is preserved between graph views and Schedule views. * Holding control key down when using regular expression search shows currently hidden nodes that match the regex search. * Pane expansion buttons now respond to clicks in entire button area. * Default text in regex search box makes searching more discoverable. Review-Url: https://codereview.chromium.org/2059193002 Cr-Commit-Position: refs/heads/master@{#36932}
This commit is contained in:
parent
ab46151aea
commit
e52907f807
@ -173,16 +173,30 @@ class GraphView extends View {
|
||||
if (d3.event.keyCode == 13) {
|
||||
graph.state.selection.clear();
|
||||
var reg = new RegExp(this.value);
|
||||
var filterFunction = function(n) {
|
||||
return (reg.exec(n.getDisplayLabel()) != null ||
|
||||
(graph.state.showTypes && reg.exec(n.getDisplayType())) ||
|
||||
reg.exec(n.opcode) != null);
|
||||
};
|
||||
if (d3.event.ctrlKey) {
|
||||
graph.nodes.forEach(function(n, i) {
|
||||
if (filterFunction(n)) {
|
||||
n.visible = true;
|
||||
}
|
||||
});
|
||||
graph.updateGraphVisibility();
|
||||
}
|
||||
var selected = graph.visibleNodes.each(function(n) {
|
||||
if (reg.exec(n.getDisplayLabel()) != null ||
|
||||
(graph.state.showTypes && reg.exec(n.getDisplayType())) ||
|
||||
reg.exec(n.opcode) != null) {
|
||||
if (filterFunction(n)) {
|
||||
graph.state.selection.select(this, true);
|
||||
}
|
||||
});
|
||||
graph.connectVisibleSelectedNodes();
|
||||
graph.updateGraphVisibility();
|
||||
this.blur();
|
||||
graph.viewSelection();
|
||||
}
|
||||
d3.event.stopPropagation();
|
||||
});
|
||||
|
||||
// listen for key events
|
||||
@ -243,9 +257,10 @@ class GraphView extends View {
|
||||
}
|
||||
|
||||
initializeContent(data, rememberedSelection) {
|
||||
this.createGraph(data);
|
||||
this.createGraph(data, rememberedSelection);
|
||||
if (rememberedSelection != null) {
|
||||
this.attachSelection(rememberedSelection);
|
||||
this.connectVisibleSelectedNodes();
|
||||
}
|
||||
this.updateGraphVisibility();
|
||||
}
|
||||
@ -259,7 +274,7 @@ class GraphView extends View {
|
||||
}
|
||||
};
|
||||
|
||||
createGraph(data) {
|
||||
createGraph(data, initiallyVisibileIds) {
|
||||
var g = this;
|
||||
g.nodes = data.nodes;
|
||||
g.nodeMap = [];
|
||||
@ -298,6 +313,11 @@ class GraphView extends View {
|
||||
});
|
||||
g.nodes.forEach(function(n, i) {
|
||||
n.visible = isNodeInitiallyVisible(n);
|
||||
if (initiallyVisibileIds != undefined) {
|
||||
if (initiallyVisibileIds.has(n.id)) {
|
||||
n.visible = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
g.fitGraphViewToWindow();
|
||||
g.updateGraphVisibility();
|
||||
@ -306,6 +326,23 @@ class GraphView extends View {
|
||||
g.viewWholeGraph();
|
||||
}
|
||||
|
||||
connectVisibleSelectedNodes() {
|
||||
var graph = this;
|
||||
graph.state.selection.selection.forEach(function(element) {
|
||||
var edgeNumber = 0;
|
||||
element.__data__.inputs.forEach(function(edge) {
|
||||
if (edge.source.visible && edge.target.visible) {
|
||||
edge.visible = true;
|
||||
}
|
||||
});
|
||||
element.__data__.outputs.forEach(function(edge) {
|
||||
if (edge.source.visible && edge.target.visible) {
|
||||
edge.visible = true;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
updateInputAndOutputBubbles() {
|
||||
var g = this;
|
||||
var s = g.visibleBubbles;
|
||||
@ -359,11 +396,11 @@ class GraphView extends View {
|
||||
|
||||
detachSelection() {
|
||||
var selection = this.state.selection.detachSelection();
|
||||
var result = new Set();
|
||||
var s = new Set();
|
||||
for (var i of selection) {
|
||||
result.add(i.__data__.id);
|
||||
s.add(i.__data__.id);
|
||||
};
|
||||
return result;
|
||||
return s;
|
||||
}
|
||||
|
||||
pathMouseDown(path, d) {
|
||||
@ -436,6 +473,17 @@ class GraphView extends View {
|
||||
});
|
||||
}
|
||||
|
||||
selectAllNodes(inEdges, filter) {
|
||||
var graph = this;
|
||||
if (!d3.event.shiftKey) {
|
||||
graph.state.selection.clear();
|
||||
}
|
||||
graph.visibleNodes.each(function(n) {
|
||||
graph.state.selection.select(this, true);
|
||||
});
|
||||
graph.updateGraphVisibility();
|
||||
}
|
||||
|
||||
svgMouseDown() {
|
||||
this.state.graphMouseDown = true;
|
||||
}
|
||||
@ -463,36 +511,109 @@ class GraphView extends View {
|
||||
// Don't handle key press repetition
|
||||
if(state.lastKeyDown !== -1) return;
|
||||
|
||||
var getEdgeFrontier = function(inEdges) {
|
||||
var getEdgeFrontier = function(inEdges, edgeFilter) {
|
||||
var frontierSet = new Set();
|
||||
var newState = true;
|
||||
if (d3.event.ctrlKey) {
|
||||
state.selection.selection.forEach(function(element) {
|
||||
var edges = inEdges ? element.__data__.inputs : element.__data__.outputs;
|
||||
var edgeNumber = 0;
|
||||
// Control key toggles edges rather than just turning them on
|
||||
edges.forEach(function(i) {
|
||||
if (edgeFilter == undefined || edgeFilter(i, edgeNumber)) {
|
||||
if (i.visible) {
|
||||
newState = false;
|
||||
}
|
||||
}
|
||||
++edgeNumber;
|
||||
});
|
||||
});
|
||||
}
|
||||
state.selection.selection.forEach(function(element) {
|
||||
var nodes = inEdges ? element.__data__.inputs : element.__data__.outputs;
|
||||
nodes.forEach(function(i) {
|
||||
i.visible = true;
|
||||
var candidate = inEdges ? i.source : i.target;
|
||||
candidate.visible = true;
|
||||
frontierSet.add(candidate);
|
||||
var edges = inEdges ? element.__data__.inputs : element.__data__.outputs;
|
||||
var edgeNumber = 0;
|
||||
edges.forEach(function(i) {
|
||||
if (edgeFilter == undefined || edgeFilter(i, edgeNumber)) {
|
||||
i.visible = newState;
|
||||
if (newState) {
|
||||
var candidate = inEdges ? i.source : i.target;
|
||||
candidate.visible = true;
|
||||
frontierSet.add(candidate);
|
||||
}
|
||||
}
|
||||
++edgeNumber;
|
||||
});
|
||||
});
|
||||
graph.updateGraphVisibility();
|
||||
return graph.visibleNodes.filter(function(n) {
|
||||
return frontierSet.has(n);
|
||||
});
|
||||
if (newState) {
|
||||
return graph.visibleNodes.filter(function(n) {
|
||||
return frontierSet.has(n);
|
||||
});
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
var selectNodesThroughEdges = function(inEdges, filter, reselect) {
|
||||
var frontier = getEdgeFrontier(inEdges, filter);
|
||||
if (frontier != undefined) {
|
||||
if (reselect) {
|
||||
if (!d3.event.shiftKey) {
|
||||
state.selection.clear();
|
||||
}
|
||||
frontier.each(function(n) {
|
||||
state.selection.select(this, true);
|
||||
});
|
||||
}
|
||||
graph.updateGraphVisibility();
|
||||
}
|
||||
allowRepetition = false;
|
||||
}
|
||||
|
||||
var allowRepetition = true;
|
||||
switch(d3.event.keyCode) {
|
||||
case 49:
|
||||
case 50:
|
||||
case 51:
|
||||
case 52:
|
||||
case 53:
|
||||
case 54:
|
||||
case 55:
|
||||
case 56:
|
||||
case 57:
|
||||
// '1'-'9'
|
||||
selectNodesThroughEdges(true,
|
||||
(edge, index) => { return index == (d3.event.keyCode - 49); },
|
||||
false);
|
||||
break;
|
||||
case 67:
|
||||
// 'c'
|
||||
selectNodesThroughEdges(true,
|
||||
(edge, index) => { return edge.type == 'control'; },
|
||||
false);
|
||||
break;
|
||||
case 69:
|
||||
// 'e'
|
||||
selectNodesThroughEdges(true,
|
||||
(edge, index) => { return edge.type == 'effect'; },
|
||||
false);
|
||||
break;
|
||||
case 79:
|
||||
// 'o'
|
||||
selectNodesThroughEdges(false, undefined, false);
|
||||
break;
|
||||
case 73:
|
||||
// 'i'
|
||||
selectNodesThroughEdges(true, undefined, false);
|
||||
break;
|
||||
case 65:
|
||||
// 'a'
|
||||
graph.selectAllNodes();
|
||||
allowRepetition = false;
|
||||
break;
|
||||
case 38:
|
||||
case 40: {
|
||||
var frontier = getEdgeFrontier(d3.event.keyCode == 38);
|
||||
if (!d3.event.shiftKey) {
|
||||
state.selection.clear();
|
||||
}
|
||||
frontier.each(function(n) {
|
||||
state.selection.select(this, true);
|
||||
});
|
||||
graph.updateGraphVisibility();
|
||||
allowRepetition = false;
|
||||
selectNodesThroughEdges(d3.event.keyCode == 38, undefined, true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -76,8 +76,8 @@ class ScheduleView extends TextView {
|
||||
],
|
||||
// Parse opcode including []
|
||||
[
|
||||
[/^[A-Za-z0-9_]+(\[[^\]]+\])?$/, NODE_STYLE, -1],
|
||||
[/^[A-Za-z0-9_]+(\[[^\]]+\])?/, NODE_STYLE, 3]
|
||||
[/^[A-Za-z0-9_]+(\[.+])?$/, NODE_STYLE, -1],
|
||||
[/^[A-Za-z0-9_]+(\[.+])?/, NODE_STYLE, 3]
|
||||
],
|
||||
// Parse optional parameters
|
||||
[
|
||||
@ -105,4 +105,23 @@ class ScheduleView extends TextView {
|
||||
this.setPatterns(patterns);
|
||||
this.setNodePositionMap(nodePositionMap);
|
||||
}
|
||||
|
||||
initializeContent(data, rememberedSelection) {
|
||||
super.initializeContent(data, rememberedSelection);
|
||||
var graph = this;
|
||||
var locations = [];
|
||||
for (var id of rememberedSelection) {
|
||||
locations.push({ node_id : id });
|
||||
}
|
||||
this.selectLocations(locations, true, false);
|
||||
}
|
||||
|
||||
detachSelection() {
|
||||
var selection = this.selection.detachSelection();
|
||||
var s = new Set();
|
||||
for (var i of selection) {
|
||||
s.add(i.location.node_id);
|
||||
};
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
padding: 0.5em;
|
||||
z-index: 5;
|
||||
opacity: 0.7;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
@ -227,7 +228,7 @@ ul.noindent {
|
||||
-webkit-margin-after: 0px;
|
||||
}
|
||||
|
||||
input:hover {
|
||||
input:hover, .collapse-pane:hover input {
|
||||
opacity: 1;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -44,6 +44,10 @@ document.onload = (function(d3){
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSourceExpanded() {
|
||||
setSourceExpanded(!sourceExpanded);
|
||||
}
|
||||
|
||||
function setSourceExpanded(newState) {
|
||||
sourceExpanded = newState;
|
||||
updatePanes();
|
||||
@ -60,6 +64,10 @@ document.onload = (function(d3){
|
||||
}
|
||||
}
|
||||
|
||||
function toggleDisassemblyExpanded() {
|
||||
setDisassemblyExpanded(!disassemblyExpanded);
|
||||
}
|
||||
|
||||
function setDisassemblyExpanded(newState) {
|
||||
disassemblyExpanded = newState;
|
||||
updatePanes();
|
||||
@ -118,26 +126,14 @@ document.onload = (function(d3){
|
||||
selectionBroker = new SelectionBroker();
|
||||
|
||||
function initializeHandlers(g) {
|
||||
d3.select("#source-expand").on("click", function(){
|
||||
setSourceExpanded(true);
|
||||
d3.select("#source-collapse").on("click", function(){
|
||||
toggleSourceExpanded(true);
|
||||
setTimeout(function(){
|
||||
g.fitGraphViewToWindow();
|
||||
}, 1000);
|
||||
});
|
||||
d3.select("#source-shrink").on("click", function(){
|
||||
setSourceExpanded(false);
|
||||
setTimeout(function(){
|
||||
g.fitGraphViewToWindow();
|
||||
}, 1000);
|
||||
});
|
||||
d3.select("#disassembly-expand").on("click", function(){
|
||||
setDisassemblyExpanded(true);
|
||||
setTimeout(function(){
|
||||
g.fitGraphViewToWindow();
|
||||
}, 1000);
|
||||
});
|
||||
d3.select("#disassembly-shrink").on("click", function(){
|
||||
setDisassemblyExpanded(false);
|
||||
d3.select("#disassembly-collapse").on("click", function(){
|
||||
toggleDisassemblyExpanded();
|
||||
setTimeout(function(){
|
||||
g.fitGraphViewToWindow();
|
||||
}, 1000);
|
||||
|
Loading…
Reference in New Issue
Block a user