mirror of
https://github.com/opennetworkinglab/onos.git
synced 2025-10-23 13:21:21 +02:00
GUI - Rebuilt Quick Help layout to allow multi-column key binding section.
Change-Id: Icada50c695ce60c8cbedb38d86434a842d935e77
This commit is contained in:
parent
2bea44e615
commit
a1a00c247e
@ -417,19 +417,23 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function setupGlobalKeys() {
|
function setupGlobalKeys() {
|
||||||
keyHandler.globalKeys = {
|
$.extend(keyHandler, {
|
||||||
slash: [quickHelp, 'Show / hide Quick Help'],
|
globalKeys: {
|
||||||
backSlash: [quickHelp, 'Show / hide Quick Help'],
|
backSlash: [quickHelp, 'Show / hide Quick Help'],
|
||||||
esc: [escapeKey, 'Dismiss dialog or cancel selections'],
|
slash: [quickHelp, 'Show / hide Quick Help'],
|
||||||
T: [toggleTheme, "Toggle theme"]
|
esc: [escapeKey, 'Dismiss dialog or cancel selections'],
|
||||||
};
|
T: [toggleTheme, "Toggle theme"]
|
||||||
// Masked keys are global key handlers that always return true.
|
},
|
||||||
// That is, the view will never see the event for that key.
|
globalFormat: ['backSlash', 'slash', 'esc', 'T'],
|
||||||
keyHandler.maskedKeys = {
|
|
||||||
slash: true,
|
// Masked keys are global key handlers that always return true.
|
||||||
backSlash: true,
|
// That is, the view will never see the event for that key.
|
||||||
T: true
|
maskedKeys: {
|
||||||
};
|
slash: true,
|
||||||
|
backSlash: true,
|
||||||
|
T: true
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function quickHelp(view, key, code, ev) {
|
function quickHelp(view, key, code, ev) {
|
||||||
|
@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
#quickhelp svg {
|
#quickhelp svg {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: 40px;
|
top: 180px;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +36,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
#quickhelp svg text.title {
|
#quickhelp svg text.title {
|
||||||
font-size: 8pt;
|
font-size: 10pt;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
text-anchor: middle;
|
text-anchor: middle;
|
||||||
fill: #999;
|
fill: #999;
|
||||||
@ -46,23 +46,21 @@
|
|||||||
fill: white;
|
fill: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
#quickhelp svg g.keyItem line {
|
#quickhelp svg g line.qhrowsep {
|
||||||
stroke: #888;
|
stroke: #888;
|
||||||
stroke-dasharray: 2 2;
|
stroke-dasharray: 2 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
#quickhelp svg text {
|
#quickhelp svg text {
|
||||||
font-size: 5pt;
|
font-size: 7pt;
|
||||||
alignment-baseline: middle;
|
alignment-baseline: middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
#quickhelp svg text.key {
|
#quickhelp svg text.key {
|
||||||
font-size: 5pt;
|
|
||||||
fill: #add;
|
fill: #add;
|
||||||
}
|
}
|
||||||
|
|
||||||
#quickhelp svg text.desc {
|
#quickhelp svg text.desc {
|
||||||
font-size: 5pt;
|
|
||||||
fill: #ddd;
|
fill: #ddd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,29 +26,35 @@
|
|||||||
(function (onos){
|
(function (onos){
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// API's
|
|
||||||
var api = onos.api;
|
|
||||||
|
|
||||||
// Config variables
|
// Config variables
|
||||||
var w = '100%',
|
var w = '100%',
|
||||||
h = '80%',
|
h = '80%',
|
||||||
fade = 500,
|
fade = 500,
|
||||||
vb = '-200 0 400 400';
|
vb = '-200 0 400 400';
|
||||||
|
|
||||||
|
// layout configuration
|
||||||
|
var pad = 10,
|
||||||
|
offy = 45,
|
||||||
|
sepYDelta = 20,
|
||||||
|
colXDelta = 16,
|
||||||
|
yTextSpc = 12,
|
||||||
|
offDesc = 8;
|
||||||
|
|
||||||
// State variables
|
// State variables
|
||||||
var data = [];
|
var data = [],
|
||||||
|
yCount;
|
||||||
|
|
||||||
// DOM elements and the like
|
// DOM elements and the like
|
||||||
var qhdiv = d3.select('#quickhelp'),
|
var qhdiv = d3.select('#quickhelp'),
|
||||||
svg = qhdiv.select('svg'),
|
svg = qhdiv.select('svg'),
|
||||||
pane,
|
pane, rect, items;
|
||||||
rect,
|
|
||||||
items,
|
|
||||||
keyAgg;
|
|
||||||
|
|
||||||
// General functions
|
// General functions
|
||||||
function isA(a) {
|
function isA(a) { return $.isArray(a) ? a : null; }
|
||||||
return $.isArray(a) ? a : null;
|
function isS(s) { return typeof s === 'string'; }
|
||||||
|
|
||||||
|
function cap(s) {
|
||||||
|
return s.replace(/^[a-z]/, function (m) { return m.toUpperCase(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
var keyDisp = {
|
var keyDisp = {
|
||||||
@ -63,144 +69,212 @@
|
|||||||
downArrow: 'D-arrow'
|
downArrow: 'D-arrow'
|
||||||
};
|
};
|
||||||
|
|
||||||
function cap(s) {
|
|
||||||
return s.replace(/^[a-z]/, function (m) { return m.toUpperCase(); });
|
|
||||||
}
|
|
||||||
|
|
||||||
function mkKeyDisp(id) {
|
function mkKeyDisp(id) {
|
||||||
var v = keyDisp[id] || id;
|
var v = keyDisp[id] || id;
|
||||||
return cap(v);
|
return cap(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
// layout configuration
|
function addSeparator(el, i) {
|
||||||
var pad = 8,
|
var y = sepYDelta/2 - 5;
|
||||||
offy = 45,
|
el.append('line')
|
||||||
dy = 10,
|
.attr({ 'class': 'qhrowsep', x1: 0, y1: y, x2: 0, y2: y });
|
||||||
offDesc = 8;
|
}
|
||||||
|
|
||||||
// D3 magic
|
function addContent(el, data, ri) {
|
||||||
function updateKeyItems() {
|
var xCount = 0,
|
||||||
var keyItems = items.selectAll('.keyItem')
|
clsPfx = 'qh-r' + ri + '-c';
|
||||||
.data(data);
|
|
||||||
|
|
||||||
var entering = keyItems.enter()
|
function addColumn(el, c, i) {
|
||||||
.append('g')
|
var cls = clsPfx + i,
|
||||||
.attr({
|
oy = 0,
|
||||||
id: function (d) { return d.id; },
|
aggKey = el.append('g').attr('visibility', 'hidden'),
|
||||||
class: 'keyItem'
|
gcol = el.append('g').attr({
|
||||||
|
'class': cls,
|
||||||
|
transform: translate(xCount, 0)
|
||||||
|
});
|
||||||
|
|
||||||
|
c.forEach(function (j) {
|
||||||
|
var k = j[0],
|
||||||
|
v = j[1];
|
||||||
|
|
||||||
|
if (k !== '-') {
|
||||||
|
aggKey.append('text').text(k);
|
||||||
|
|
||||||
|
gcol.append('text').text(k)
|
||||||
|
.attr({
|
||||||
|
'class': 'key',
|
||||||
|
y: oy
|
||||||
|
});
|
||||||
|
gcol.append('text').text(v)
|
||||||
|
.attr({
|
||||||
|
'class': 'desc',
|
||||||
|
y: oy
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
oy += yTextSpc;
|
||||||
});
|
});
|
||||||
|
|
||||||
entering.each(function (d, i) {
|
// adjust position of descriptions, based on widest key
|
||||||
|
var kbox = aggKey.node().getBBox(),
|
||||||
|
ox = kbox.width + offDesc;
|
||||||
|
gcol.selectAll('.desc').attr('x', ox);
|
||||||
|
aggKey.remove();
|
||||||
|
|
||||||
|
// now update x-offset for next column
|
||||||
|
var bbox = gcol.node().getBBox();
|
||||||
|
xCount += bbox.width + colXDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
data.forEach(function (d, i) {
|
||||||
|
addColumn(el, d, i);
|
||||||
|
});
|
||||||
|
|
||||||
|
// finally, return the height of the row..
|
||||||
|
return el.node().getBBox().height;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateKeyItems() {
|
||||||
|
var rows = items.selectAll('.qhRow').data(data);
|
||||||
|
|
||||||
|
yCount = offy;
|
||||||
|
|
||||||
|
var entering = rows.enter()
|
||||||
|
.append('g')
|
||||||
|
.attr({
|
||||||
|
'class': 'qhrow'
|
||||||
|
});
|
||||||
|
|
||||||
|
entering.each(function (r, i) {
|
||||||
var el = d3.select(this),
|
var el = d3.select(this),
|
||||||
y = offy + dy * i;
|
sep = r.type === 'sep',
|
||||||
|
dy;
|
||||||
|
|
||||||
if (d.id[0] === '_') {
|
el.attr('transform', translate(0, yCount));
|
||||||
el.append('line')
|
|
||||||
.attr({ x1: 0, y1: y, x2: 1, y2: y});
|
if (sep) {
|
||||||
|
addSeparator(el, i);
|
||||||
|
yCount += sepYDelta;
|
||||||
} else {
|
} else {
|
||||||
el.append('text')
|
dy = addContent(el, r.data, i);
|
||||||
.text(d.key)
|
yCount += dy;
|
||||||
.attr({
|
|
||||||
class: 'key',
|
|
||||||
x: 0,
|
|
||||||
y: y
|
|
||||||
});
|
|
||||||
// NOTE: used for sizing column width...
|
|
||||||
keyAgg.append('text').text(d.key).attr('class', 'key');
|
|
||||||
|
|
||||||
el.append('text')
|
|
||||||
.text(d.desc)
|
|
||||||
.attr({
|
|
||||||
class: 'desc',
|
|
||||||
x: offDesc,
|
|
||||||
y: y
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var kbox = keyAgg.node().getBBox();
|
// size the backing rectangle
|
||||||
items.selectAll('.desc').attr('x', kbox.width + offDesc);
|
var ibox = items.node().getBBox(),
|
||||||
|
paneW = ibox.width + pad * 2,
|
||||||
|
paneH = ibox.height + offy;
|
||||||
|
|
||||||
var box = items.node().getBBox(),
|
items.selectAll('.qhrowsep').attr('x2', ibox.width);
|
||||||
paneW = box.width + pad * 2,
|
|
||||||
paneH = box.height + offy;
|
|
||||||
|
|
||||||
items.selectAll('line').attr('x2', box.width);
|
|
||||||
items.attr('transform', translate(-paneW/2, -pad));
|
items.attr('transform', translate(-paneW/2, -pad));
|
||||||
rect.attr({
|
rect.attr({
|
||||||
width: paneW,
|
width: paneW,
|
||||||
height: paneH,
|
height: paneH,
|
||||||
transform: translate(-paneW/2-pad, 0)
|
transform: translate(-paneW/2-pad, 0)
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function translate(x, y) {
|
function translate(x, y) {
|
||||||
return 'translate(' + x + ',' + y + ')';
|
return 'translate(' + x + ',' + y + ')';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function checkFmt(fmt) {
|
||||||
|
// should be a single array of keys,
|
||||||
|
// or array of arrays of keys (one per column).
|
||||||
|
// return null if there is a problem.
|
||||||
|
var a = isA(fmt),
|
||||||
|
n = a && a.length,
|
||||||
|
ns = 0,
|
||||||
|
na = 0;
|
||||||
|
|
||||||
|
if (n) {
|
||||||
|
// it is an array which has some content
|
||||||
|
a.forEach(function (d) {
|
||||||
|
isA(d) && na++;
|
||||||
|
isS(d) && ns++;
|
||||||
|
});
|
||||||
|
if (na === n || ns === n) {
|
||||||
|
// all arrays or all strings...
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildBlock(map, fmt) {
|
||||||
|
var b = [];
|
||||||
|
fmt.forEach(function (k) {
|
||||||
|
var v = map.get(k),
|
||||||
|
a = isA(v),
|
||||||
|
d = (a && a[1]);
|
||||||
|
|
||||||
|
// '-' marks a separator; d is the description
|
||||||
|
if (k === '-' || d) {
|
||||||
|
b.push([mkKeyDisp(k), d]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
function emptyRow() {
|
||||||
|
return { type: 'row', data: []};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mkArrRow(fmt) {
|
||||||
|
var d = emptyRow();
|
||||||
|
d.data.push(fmt);
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mkColumnarRow(map, fmt) {
|
||||||
|
var d = emptyRow();
|
||||||
|
fmt.forEach(function (a) {
|
||||||
|
d.data.push(buildBlock(map, a));
|
||||||
|
});
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mkMapRow(map, fmt) {
|
||||||
|
var d = emptyRow();
|
||||||
|
d.data.push(buildBlock(map, fmt));
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addRow(row) {
|
||||||
|
var d = row || { type: 'sep' };
|
||||||
|
data.push(d);
|
||||||
|
}
|
||||||
|
|
||||||
function aggregateData(bindings) {
|
function aggregateData(bindings) {
|
||||||
var hf = '_helpFormat',
|
var hf = '_helpFormat',
|
||||||
gmap = d3.map(bindings.globalKeys),
|
gmap = d3.map(bindings.globalKeys),
|
||||||
|
gfmt = bindings.globalFormat,
|
||||||
vmap = d3.map(bindings.viewKeys),
|
vmap = d3.map(bindings.viewKeys),
|
||||||
fmt = vmap.get(hf),
|
|
||||||
vgest = bindings.viewGestures,
|
vgest = bindings.viewGestures,
|
||||||
gkeys = gmap.keys(),
|
vfmt, vkeys;
|
||||||
vkeys,
|
|
||||||
sep = 0;
|
|
||||||
|
|
||||||
// filter out help format entry
|
// filter out help format entry
|
||||||
|
vfmt = checkFmt(vmap.get(hf));
|
||||||
vmap.remove(hf);
|
vmap.remove(hf);
|
||||||
vkeys = vmap.keys(),
|
|
||||||
|
|
||||||
gkeys.sort();
|
// if bad (or no) format, fallback to sorted keys
|
||||||
vkeys.sort();
|
if (!vfmt) {
|
||||||
|
vkeys = vmap.keys();
|
||||||
|
vfmt = vkeys.sort();
|
||||||
|
}
|
||||||
|
|
||||||
data = [];
|
data = [];
|
||||||
gkeys.forEach(function (k) {
|
|
||||||
addItem('glob', k, gmap.get(k));
|
|
||||||
});
|
|
||||||
addItem('sep');
|
|
||||||
vkeys.forEach(function (k) {
|
|
||||||
addItem('view', k, vmap.get(k));
|
|
||||||
});
|
|
||||||
addItem('sep');
|
|
||||||
vgest.forEach(function (g) {
|
|
||||||
if (g.length === 2) {
|
|
||||||
addItem('gest', g[0], g[1]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
addRow(mkMapRow(gmap, gfmt));
|
||||||
function addItem(type, k, d) {
|
addRow();
|
||||||
var id = type + '-' + k,
|
addRow(isA(vfmt[0]) ? mkColumnarRow(vmap, vfmt) : mkMapRow(vmap, vfmt));
|
||||||
a = isA(d),
|
addRow();
|
||||||
desc = a && a[1];
|
addRow(mkArrRow(vgest));
|
||||||
|
|
||||||
if (type === 'sep') {
|
|
||||||
data.push({
|
|
||||||
id: '_' + sep++,
|
|
||||||
type: type
|
|
||||||
});
|
|
||||||
} else if (type === 'gest') {
|
|
||||||
data.push({
|
|
||||||
id: id,
|
|
||||||
type: type,
|
|
||||||
key: k,
|
|
||||||
desc: d
|
|
||||||
});
|
|
||||||
} else if (desc) {
|
|
||||||
data.push(
|
|
||||||
{
|
|
||||||
id: id,
|
|
||||||
type: type,
|
|
||||||
key: mkKeyDisp(k),
|
|
||||||
desc: desc
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function popBind(bindings) {
|
function popBind(bindings) {
|
||||||
pane = svg.append('g')
|
pane = svg.append('g')
|
||||||
.attr({
|
.attr({
|
||||||
@ -220,8 +294,6 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
items = pane.append('g');
|
items = pane.append('g');
|
||||||
keyAgg = pane.append('g').style('visibility', 'hidden');
|
|
||||||
|
|
||||||
aggregateData(bindings);
|
aggregateData(bindings);
|
||||||
updateKeyItems();
|
updateKeyItems();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user