GUI -- Key Bindings pop-up (new branch)
Change-Id: I544c80b1ce78c231985d7104f60b59bba3b7911e
Showing
4 changed files
with
137 additions
and
85 deletions
| ... | @@ -23,13 +23,41 @@ | ... | @@ -23,13 +23,41 @@ |
| 23 | #keymap svg { | 23 | #keymap svg { |
| 24 | position: absolute; | 24 | position: absolute; |
| 25 | bottom: 40px; | 25 | bottom: 40px; |
| 26 | - opacity: 0.5; | 26 | + opacity: 0.7; |
| 27 | +} | ||
| 28 | + | ||
| 29 | +#keymap svg g.pane { | ||
| 30 | + fill: black; | ||
| 27 | } | 31 | } |
| 28 | 32 | ||
| 29 | #keymap svg text.title { | 33 | #keymap svg text.title { |
| 30 | font-size: 12pt; | 34 | font-size: 12pt; |
| 31 | font-style: italic; | 35 | font-style: italic; |
| 32 | - fill: #666; | ||
| 33 | text-anchor: middle; | 36 | text-anchor: middle; |
| 37 | + fill: #444; | ||
| 38 | +} | ||
| 39 | + | ||
| 40 | +#keymap svg g.keyItem { | ||
| 41 | + fill: white; | ||
| 42 | +} | ||
| 43 | + | ||
| 44 | +#keymap svg g.keyItem line { | ||
| 45 | + stroke: #444; | ||
| 46 | + stroke-dasharray: 4 4; | ||
| 47 | +} | ||
| 48 | + | ||
| 49 | +#keymap svg text { | ||
| 50 | + font-size: 10pt; | ||
| 51 | + alignment-baseline: middle; | ||
| 52 | +} | ||
| 53 | + | ||
| 54 | +#keymap svg text.key { | ||
| 55 | + font-size: 10pt; | ||
| 56 | + fill: #8aa; | ||
| 57 | +} | ||
| 58 | + | ||
| 59 | +#keymap svg text.desc { | ||
| 60 | + font-size: 10pt; | ||
| 61 | + fill: #888; | ||
| 34 | } | 62 | } |
| 35 | 63 | ... | ... |
| ... | @@ -33,9 +33,14 @@ | ... | @@ -33,9 +33,14 @@ |
| 33 | var w = '100%', | 33 | var w = '100%', |
| 34 | h = '80%', | 34 | h = '80%', |
| 35 | fade = 750, | 35 | fade = 750, |
| 36 | - vb = '-200 -200 400 400', | 36 | + vb = '-220 -220 440 440', |
| 37 | - xpad = 20, | 37 | + paneW = 400, |
| 38 | - ypad = 10; | 38 | + paneH = 340, |
| 39 | + offy = 65, | ||
| 40 | + dy = 20, | ||
| 41 | + offKey = 40, | ||
| 42 | + offDesc = offKey + 50, | ||
| 43 | + lineW = paneW - (2*offKey); | ||
| 39 | 44 | ||
| 40 | // State variables | 45 | // State variables |
| 41 | var data = []; | 46 | var data = []; |
| ... | @@ -43,104 +48,121 @@ | ... | @@ -43,104 +48,121 @@ |
| 43 | // DOM elements and the like | 48 | // DOM elements and the like |
| 44 | var kmdiv = d3.select('#keymap'); | 49 | var kmdiv = d3.select('#keymap'); |
| 45 | 50 | ||
| 46 | - function computeBox(el) { | 51 | + function isA(a) { |
| 47 | - var text = el.select('text'), | 52 | + return $.isArray(a) ? a : null; |
| 48 | - box = text.node().getBBox(); | 53 | + } |
| 49 | - | ||
| 50 | - // center | ||
| 51 | - box.x = -box.width / 2; | ||
| 52 | - box.y = -box.height / 2; | ||
| 53 | 54 | ||
| 54 | - // add some padding | ||
| 55 | - box.x -= xpad; | ||
| 56 | - box.width += xpad * 2; | ||
| 57 | - box.y -= ypad; | ||
| 58 | - box.height += ypad * 2; | ||
| 59 | 55 | ||
| 60 | - return box; | 56 | + var svg = kmdiv.select('svg'), |
| 61 | - } | 57 | + pane; |
| 62 | 58 | ||
| 63 | - function updateKeymap() { | 59 | + function updateKeyItems() { |
| 64 | - var items = svg.selectAll('.bindingItem') | 60 | + var items = pane.selectAll('.keyItem') |
| 65 | .data(data); | 61 | .data(data); |
| 66 | 62 | ||
| 67 | var entering = items.enter() | 63 | var entering = items.enter() |
| 68 | .append('g') | 64 | .append('g') |
| 69 | .attr({ | 65 | .attr({ |
| 70 | - class: 'bindingItem', | 66 | + id: function (d) { return d.id; }, |
| 71 | - opacity: 0 | 67 | + class: 'keyItem' |
| 72 | - }) | 68 | + }); |
| 73 | - .transition() | ||
| 74 | - .duration(fade) | ||
| 75 | - .attr('opacity', 1); | ||
| 76 | 69 | ||
| 77 | - entering.each(function (d) { | 70 | + entering.each(function (d, i) { |
| 78 | var el = d3.select(this), | 71 | var el = d3.select(this), |
| 79 | - box; | 72 | + y = offy + dy * i; |
| 80 | - | 73 | + |
| 81 | - d.el = el; | 74 | + if (d.id === '_') { |
| 82 | - el.append('rect').attr({ rx: 10, ry: 10}); | 75 | + el.append('line') |
| 83 | - el.append('text').text(d.label); | 76 | + .attr({ |
| 84 | - box = computeBox(el); | 77 | + class: 'sep', |
| 85 | - el.select('rect').attr(box); | 78 | + x1: offKey, |
| 79 | + y1: y, | ||
| 80 | + x2: offKey + lineW, | ||
| 81 | + y2: y | ||
| 82 | + }); | ||
| 83 | + } else { | ||
| 84 | + el.append('text') | ||
| 85 | + .text(d.key) | ||
| 86 | + .attr({ | ||
| 87 | + class: 'key', | ||
| 88 | + x: offKey, | ||
| 89 | + y: y | ||
| 90 | + }); | ||
| 91 | + | ||
| 92 | + el.append('text') | ||
| 93 | + .text(d.desc) | ||
| 94 | + .attr({ | ||
| 95 | + class: 'desc', | ||
| 96 | + x: offDesc, | ||
| 97 | + y: y | ||
| 98 | + }); | ||
| 99 | + } | ||
| 86 | }); | 100 | }); |
| 87 | - | ||
| 88 | - items.exit() | ||
| 89 | - .transition() | ||
| 90 | - .duration(fade) | ||
| 91 | - .attr({ opacity: 0}) | ||
| 92 | - .remove(); | ||
| 93 | } | 101 | } |
| 94 | 102 | ||
| 95 | - function clearFlash() { | 103 | + function aggregateData(bindings) { |
| 96 | - if (timer) { | 104 | + var gmap = d3.map(bindings.globalKeys), |
| 97 | - clearInterval(timer); | 105 | + vmap = d3.map(bindings.viewKeys), |
| 98 | - } | 106 | + gkeys = gmap.keys(), |
| 107 | + vkeys = vmap.keys(); | ||
| 108 | + | ||
| 109 | + gkeys.sort(); | ||
| 110 | + vkeys.sort(); | ||
| 111 | + | ||
| 99 | data = []; | 112 | data = []; |
| 100 | - updateFeedback(); | 113 | + gkeys.forEach(function (k) { |
| 101 | - } | 114 | + addItem('global', k, gmap.get(k)); |
| 115 | + }); | ||
| 116 | + addItem('separator'); | ||
| 117 | + vkeys.forEach(function (k) { | ||
| 118 | + addItem('view', k, vmap.get(k)); | ||
| 119 | + }); | ||
| 102 | 120 | ||
| 103 | - // for now, simply display some text feedback | 121 | + function addItem(type, k, d) { |
| 104 | - function flash(text) { | 122 | + var id = type + '-' + k, |
| 105 | - // cancel old scheduled event if there was one | 123 | + a = isA(d), |
| 106 | - if (timer) { | 124 | + desc = a && a[1]; |
| 107 | - clearInterval(timer); | 125 | + if (desc) { |
| 126 | + data.push( | ||
| 127 | + { | ||
| 128 | + id: id, | ||
| 129 | + type: type, | ||
| 130 | + key: k, | ||
| 131 | + desc: desc | ||
| 132 | + } | ||
| 133 | + ); | ||
| 134 | + } else if (type === 'separator') { | ||
| 135 | + data.push({ | ||
| 136 | + id: '_', | ||
| 137 | + type: type | ||
| 138 | + }); | ||
| 139 | + } | ||
| 108 | } | 140 | } |
| 109 | - timer = setInterval(function () { | ||
| 110 | - clearFlash(); | ||
| 111 | - }, showFor); | ||
| 112 | - | ||
| 113 | - data = [{ | ||
| 114 | - label: text | ||
| 115 | - }]; | ||
| 116 | - updateFeedback(); | ||
| 117 | - } | ||
| 118 | 141 | ||
| 119 | - // ===================================== | 142 | + } |
| 120 | - var svg = kmdiv.select('svg'); | ||
| 121 | 143 | ||
| 122 | function populateBindings(bindings) { | 144 | function populateBindings(bindings) { |
| 123 | svg.append('g') | 145 | svg.append('g') |
| 124 | .attr({ | 146 | .attr({ |
| 125 | class: 'keyBindings', | 147 | class: 'keyBindings', |
| 126 | - transform: 'translate(-200,-120)', | 148 | + transform: 'translate(-200,-200)', |
| 127 | opacity: 0 | 149 | opacity: 0 |
| 128 | }) | 150 | }) |
| 129 | .transition() | 151 | .transition() |
| 130 | .duration(fade) | 152 | .duration(fade) |
| 131 | .attr('opacity', 1); | 153 | .attr('opacity', 1); |
| 132 | 154 | ||
| 133 | - var g = svg.select('g'); | 155 | + pane = svg.select('g'); |
| 134 | 156 | ||
| 135 | - g.append('rect') | 157 | + pane.append('rect') |
| 136 | .attr({ | 158 | .attr({ |
| 137 | - width: 400, | 159 | + width: paneW, |
| 138 | - height: 240, | 160 | + height: paneH, |
| 139 | rx: 8 | 161 | rx: 8 |
| 140 | }); | 162 | }); |
| 141 | 163 | ||
| 142 | - g.append('text') | 164 | + pane.append('text') |
| 143 | - .text('Key Bindings') | 165 | + .text('Keyboard Shortcuts') |
| 144 | .attr({ | 166 | .attr({ |
| 145 | x: 200, | 167 | x: 200, |
| 146 | y: 0, | 168 | y: 0, |
| ... | @@ -148,11 +170,12 @@ | ... | @@ -148,11 +170,12 @@ |
| 148 | class: 'title' | 170 | class: 'title' |
| 149 | }); | 171 | }); |
| 150 | 172 | ||
| 151 | - // TODO: append .keyItems to rectangle | 173 | + aggregateData(bindings); |
| 174 | + updateKeyItems(); | ||
| 152 | } | 175 | } |
| 153 | 176 | ||
| 154 | function fadeBindings() { | 177 | function fadeBindings() { |
| 155 | - svg.selectAll('g') | 178 | + svg.selectAll('g.keyBindings') |
| 156 | .transition() | 179 | .transition() |
| 157 | .duration(fade) | 180 | .duration(fade) |
| 158 | .attr('opacity', 0); | 181 | .attr('opacity', 0); |
| ... | @@ -178,7 +201,8 @@ | ... | @@ -178,7 +201,8 @@ |
| 178 | if (svg.empty()) { | 201 | if (svg.empty()) { |
| 179 | addSvg(); | 202 | addSvg(); |
| 180 | populateBindings(bindings); | 203 | populateBindings(bindings); |
| 181 | - console.log("SHOW KEY MAP"); | 204 | + } else { |
| 205 | + hideKeyMap(); | ||
| 182 | } | 206 | } |
| 183 | } | 207 | } |
| 184 | 208 | ||
| ... | @@ -187,7 +211,6 @@ | ... | @@ -187,7 +211,6 @@ |
| 187 | if (!svg.empty()) { | 211 | if (!svg.empty()) { |
| 188 | fadeBindings(); | 212 | fadeBindings(); |
| 189 | removeSvg(); | 213 | removeSvg(); |
| 190 | - console.log("HIDE KEY MAP"); | ||
| 191 | return true; | 214 | return true; |
| 192 | } | 215 | } |
| 193 | return false; | 216 | return false; | ... | ... |
| ... | @@ -413,9 +413,9 @@ | ... | @@ -413,9 +413,9 @@ |
| 413 | 413 | ||
| 414 | function setupGlobalKeys() { | 414 | function setupGlobalKeys() { |
| 415 | keyHandler.globalKeys = { | 415 | keyHandler.globalKeys = { |
| 416 | - slash: keyMap, | 416 | + slash: [keyMap, 'Show / hide keyboard shortcuts'], |
| 417 | - esc: escapeKey, | 417 | + esc: [escapeKey, 'Dismiss dialog or cancel selections'], |
| 418 | - T: toggleTheme | 418 | + T: [toggleTheme, "Toggle theme"] |
| 419 | }; | 419 | }; |
| 420 | // Masked keys are global key handlers that always return true. | 420 | // Masked keys are global key handlers that always return true. |
| 421 | // That is, the view will never see the event for that key. | 421 | // That is, the view will never see the event for that key. |
| ... | @@ -476,7 +476,8 @@ | ... | @@ -476,7 +476,8 @@ |
| 476 | var event = d3.event, | 476 | var event = d3.event, |
| 477 | keyCode = event.keyCode, | 477 | keyCode = event.keyCode, |
| 478 | key = whatKey(keyCode), | 478 | key = whatKey(keyCode), |
| 479 | - gcb = isF(keyHandler.globalKeys[key]), | 479 | + gk = keyHandler.globalKeys[key], |
| 480 | + gcb = isF(gk) || (isA(gk) && isF(gk[0])), | ||
| 480 | vk = keyHandler.viewKeys[key], | 481 | vk = keyHandler.viewKeys[key], |
| 481 | vcb = isF(vk) || (isA(vk) && isF(vk[0])) || isF(keyHandler.viewFn); | 482 | vcb = isF(vk) || (isA(vk) && isF(vk[0])) || isF(keyHandler.viewFn); |
| 482 | 483 | ... | ... |
| ... | @@ -144,12 +144,12 @@ | ... | @@ -144,12 +144,12 @@ |
| 144 | B: [toggleBg, 'Toggle background image'], | 144 | B: [toggleBg, 'Toggle background image'], |
| 145 | L: [cycleLabels, 'Cycle Device labels'], | 145 | L: [cycleLabels, 'Cycle Device labels'], |
| 146 | P: togglePorts, | 146 | P: togglePorts, |
| 147 | - U: unpin, | 147 | + U: [unpin, 'Unpin node'], |
| 148 | - R: resetZoomPan, | 148 | + R: [resetZoomPan, 'Reset zoom/pan'], |
| 149 | - H: toggleHover, | 149 | + H: [cycleHoverMode, 'Cycle hover mode'], |
| 150 | - V: showTrafficAction, | 150 | + V: [showTrafficAction, 'Show traffic'], |
| 151 | - A: showAllTrafficAction, | 151 | + A: [showAllTrafficAction, 'Show all traffic'], |
| 152 | - F: showDeviceLinkFlowsAction, | 152 | + F: [showDeviceLinkFlowsAction, 'Show device link flows'], |
| 153 | esc: handleEscape | 153 | esc: handleEscape |
| 154 | }; | 154 | }; |
| 155 | 155 | ||
| ... | @@ -322,7 +322,7 @@ | ... | @@ -322,7 +322,7 @@ |
| 322 | }); | 322 | }); |
| 323 | } | 323 | } |
| 324 | 324 | ||
| 325 | - function toggleHover(view) { | 325 | + function cycleHoverMode(view) { |
| 326 | hoverMode++; | 326 | hoverMode++; |
| 327 | if (hoverMode === hoverModes.length) { | 327 | if (hoverMode === hoverModes.length) { |
| 328 | hoverMode = 0; | 328 | hoverMode = 0; | ... | ... |
-
Please register or login to post a comment