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