Simon Hunt

GUI -- Adding Key Bindings cheat sheet... WIP.

Change-Id: Idf5ea6d405d9a5dfb83f43c0a4da458727bd9ab4
...@@ -45,11 +45,13 @@ ...@@ -45,11 +45,13 @@
45 // DOM elements and the like 45 // DOM elements and the like
46 var fb = d3.select('#feedback'); 46 var fb = d3.select('#feedback');
47 47
48 - var svg = fb.append('svg').attr({ 48 + var svg;
49 - width: w, 49 +
50 - height: h, 50 + //var svg = fb.append('svg').attr({
51 - viewBox: vb 51 + // width: w,
52 - }); 52 + // height: h,
53 + // viewBox: vb
54 + //});
53 55
54 function computeBox(el) { 56 function computeBox(el) {
55 var text = el.select('text'), 57 var text = el.select('text'),
...@@ -69,6 +71,14 @@ ...@@ -69,6 +71,14 @@
69 } 71 }
70 72
71 function updateFeedback() { 73 function updateFeedback() {
74 + if (!svg) {
75 + svg = fb.append('svg').attr({
76 + width: w,
77 + height: h,
78 + viewBox: vb
79 + });
80 + }
81 +
72 var items = svg.selectAll('.feedbackItem') 82 var items = svg.selectAll('.feedbackItem')
73 .data(data); 83 .data(data);
74 84
...@@ -98,6 +108,13 @@ ...@@ -98,6 +108,13 @@
98 .duration(fade) 108 .duration(fade)
99 .attr({ opacity: 0}) 109 .attr({ opacity: 0})
100 .remove(); 110 .remove();
111 +
112 + if (svg && data.length === 0) {
113 + svg.transition()
114 + .delay(fade + 10)
115 + .remove();
116 + svg = null;
117 + }
101 } 118 }
102 119
103 function clearFlash() { 120 function clearFlash() {
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
43 <link rel="stylesheet" href="mast2.css"> 43 <link rel="stylesheet" href="mast2.css">
44 <link rel="stylesheet" href="floatPanel.css"> 44 <link rel="stylesheet" href="floatPanel.css">
45 <link rel="stylesheet" href="feedback.css"> 45 <link rel="stylesheet" href="feedback.css">
46 + <link rel="stylesheet" href="keymap.css">
46 47
47 <!-- This is where contributed stylesheets get INJECTED --> 48 <!-- This is where contributed stylesheets get INJECTED -->
48 <!-- TODO: replace with template marker and inject refs server-side --> 49 <!-- TODO: replace with template marker and inject refs server-side -->
...@@ -75,6 +76,9 @@ ...@@ -75,6 +76,9 @@
75 <div id="feedback"> 76 <div id="feedback">
76 <!-- NOTE: feedback to user --> 77 <!-- NOTE: feedback to user -->
77 </div> 78 </div>
79 + <div id="keymap">
80 + <!-- NOTE: key bindings map -->
81 + </div>
78 </div> 82 </div>
79 83
80 <!-- Initialize the UI...--> 84 <!-- Initialize the UI...-->
...@@ -94,6 +98,7 @@ ...@@ -94,6 +98,7 @@
94 <!-- Framework module files included here --> 98 <!-- Framework module files included here -->
95 <script src="mast2.js"></script> 99 <script src="mast2.js"></script>
96 <script src="feedback.js"></script> 100 <script src="feedback.js"></script>
101 + <script src="keymap.js"></script>
97 102
98 <!-- View Module Templates; REMOVE THESE LINES, FOR PRODUCTION --> 103 <!-- View Module Templates; REMOVE THESE LINES, FOR PRODUCTION -->
99 <script src="module-svg-template.js"></script> 104 <script src="module-svg-template.js"></script>
......
1 +/*
2 + * Copyright 2014 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +/*
18 + ONOS GUI -- Key map layer -- CSS file
19 +
20 + @author Simon Hunt
21 + */
22 +
23 +#keymap svg {
24 + position: absolute;
25 + bottom: 40px;
26 + opacity: 0.5;
27 +}
28 +
29 +#keymap svg text.title {
30 + font-size: 12pt;
31 + font-style: italic;
32 + fill: #666;
33 + text-anchor: middle;
34 +}
35 +
1 +/*
2 + * Copyright 2014 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +
17 +/*
18 + ONOS GUI -- Keymap Layer
19 +
20 + Defines the key-map layer for the UI. Used to give user a list of
21 + key bindings; both global, and for the current view.
22 +
23 + @author Simon Hunt
24 + */
25 +
26 +(function (onos){
27 + 'use strict';
28 +
29 + // API's
30 + var api = onos.api;
31 +
32 + // Config variables
33 + var w = '100%',
34 + h = '80%',
35 + fade = 750,
36 + vb = '-200 -200 400 400',
37 + xpad = 20,
38 + ypad = 10;
39 +
40 + // State variables
41 + var data = [];
42 +
43 + // DOM elements and the like
44 + var kmdiv = d3.select('#keymap');
45 +
46 + function computeBox(el) {
47 + var text = el.select('text'),
48 + box = text.node().getBBox();
49 +
50 + // center
51 + box.x = -box.width / 2;
52 + box.y = -box.height / 2;
53 +
54 + // add some padding
55 + box.x -= xpad;
56 + box.width += xpad * 2;
57 + box.y -= ypad;
58 + box.height += ypad * 2;
59 +
60 + return box;
61 + }
62 +
63 + function updateKeymap() {
64 + var items = svg.selectAll('.bindingItem')
65 + .data(data);
66 +
67 + var entering = items.enter()
68 + .append('g')
69 + .attr({
70 + class: 'bindingItem',
71 + opacity: 0
72 + })
73 + .transition()
74 + .duration(fade)
75 + .attr('opacity', 1);
76 +
77 + entering.each(function (d) {
78 + var el = d3.select(this),
79 + box;
80 +
81 + d.el = el;
82 + el.append('rect').attr({ rx: 10, ry: 10});
83 + el.append('text').text(d.label);
84 + box = computeBox(el);
85 + el.select('rect').attr(box);
86 + });
87 +
88 + items.exit()
89 + .transition()
90 + .duration(fade)
91 + .attr({ opacity: 0})
92 + .remove();
93 + }
94 +
95 + function clearFlash() {
96 + if (timer) {
97 + clearInterval(timer);
98 + }
99 + data = [];
100 + updateFeedback();
101 + }
102 +
103 + // for now, simply display some text feedback
104 + function flash(text) {
105 + // cancel old scheduled event if there was one
106 + if (timer) {
107 + clearInterval(timer);
108 + }
109 + timer = setInterval(function () {
110 + clearFlash();
111 + }, showFor);
112 +
113 + data = [{
114 + label: text
115 + }];
116 + updateFeedback();
117 + }
118 +
119 + // =====================================
120 + var svg = kmdiv.select('svg');
121 +
122 + function populateBindings(bindings) {
123 + svg.append('g')
124 + .attr({
125 + class: 'keyBindings',
126 + transform: 'translate(-200,-120)',
127 + opacity: 0
128 + })
129 + .transition()
130 + .duration(fade)
131 + .attr('opacity', 1);
132 +
133 + var g = svg.select('g');
134 +
135 + g.append('rect')
136 + .attr({
137 + width: 400,
138 + height: 240,
139 + rx: 8
140 + });
141 +
142 + g.append('text')
143 + .text('Key Bindings')
144 + .attr({
145 + x: 200,
146 + y: 0,
147 + dy: '1.4em',
148 + class: 'title'
149 + });
150 +
151 + // TODO: append .keyItems to rectangle
152 + }
153 +
154 + function fadeBindings() {
155 + svg.selectAll('g')
156 + .transition()
157 + .duration(fade)
158 + .attr('opacity', 0);
159 + }
160 +
161 + function addSvg() {
162 + svg = kmdiv.append('svg')
163 + .attr({
164 + width: w,
165 + height: h,
166 + viewBox: vb
167 + });
168 + }
169 +
170 + function removeSvg() {
171 + svg.transition()
172 + .delay(fade + 20)
173 + .remove();
174 + }
175 +
176 + function showKeyMap(bindings) {
177 + svg = kmdiv.select('svg');
178 + if (svg.empty()) {
179 + addSvg();
180 + populateBindings(bindings);
181 + console.log("SHOW KEY MAP");
182 + }
183 + }
184 +
185 + function hideKeyMap() {
186 + svg = kmdiv.select('svg');
187 + if (!svg.empty()) {
188 + fadeBindings();
189 + removeSvg();
190 + console.log("HIDE KEY MAP");
191 + return true;
192 + }
193 + return false;
194 + }
195 +
196 + onos.ui.addLib('keymap', {
197 + show: showKeyMap,
198 + hide: hideKeyMap
199 + });
200 +}(ONOS));
...@@ -93,6 +93,7 @@ ...@@ -93,6 +93,7 @@
93 case 40: return 'downArrow'; 93 case 40: return 'downArrow';
94 case 91: return 'cmdLeft'; 94 case 91: return 'cmdLeft';
95 case 93: return 'cmdRight'; 95 case 93: return 'cmdRight';
96 + case 191: return 'slash';
96 default: 97 default:
97 if ((code >= 48 && code <= 57) || 98 if ((code >= 48 && code <= 57) ||
98 (code >= 65 && code <= 90)) { 99 (code >= 65 && code <= 90)) {
...@@ -268,6 +269,11 @@ ...@@ -268,6 +269,11 @@
268 return $.isFunction(f) ? f : null; 269 return $.isFunction(f) ? f : null;
269 } 270 }
270 271
272 + // returns the reference if it is an array, null otherwise
273 + function isA(a) {
274 + return $.isArray(a) ? a : null;
275 + }
276 +
271 // .......................................................... 277 // ..........................................................
272 // View life-cycle functions 278 // View life-cycle functions
273 279
...@@ -407,17 +413,27 @@ ...@@ -407,17 +413,27 @@
407 413
408 function setupGlobalKeys() { 414 function setupGlobalKeys() {
409 keyHandler.globalKeys = { 415 keyHandler.globalKeys = {
416 + slash: keyMap,
410 esc: escapeKey, 417 esc: escapeKey,
411 T: toggleTheme 418 T: toggleTheme
412 }; 419 };
413 // Masked keys are global key handlers that always return true. 420 // Masked keys are global key handlers that always return true.
414 // 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.
415 keyHandler.maskedKeys = { 422 keyHandler.maskedKeys = {
423 + slash: true,
416 T: true 424 T: true
417 }; 425 };
418 } 426 }
419 427
428 + function keyMap(view, key, code, ev) {
429 + libApi.keymap.show(keyHandler);
430 + return true;
431 + }
432 +
420 function escapeKey(view, key, code, ev) { 433 function escapeKey(view, key, code, ev) {
434 + if (libApi.keymap.hide()) {
435 + return true;
436 + }
421 if (alerts.open) { 437 if (alerts.open) {
422 closeAlerts(); 438 closeAlerts();
423 return true; 439 return true;
...@@ -461,7 +477,8 @@ ...@@ -461,7 +477,8 @@
461 keyCode = event.keyCode, 477 keyCode = event.keyCode,
462 key = whatKey(keyCode), 478 key = whatKey(keyCode),
463 gcb = isF(keyHandler.globalKeys[key]), 479 gcb = isF(keyHandler.globalKeys[key]),
464 - vcb = isF(keyHandler.viewKeys[key]) || isF(keyHandler.viewFn); 480 + vk = keyHandler.viewKeys[key],
481 + vcb = isF(vk) || (isA(vk) && isF(vk[0])) || isF(keyHandler.viewFn);
465 482
466 // global callback? 483 // global callback?
467 if (gcb && gcb(current.view.token(), key, keyCode, event)) { 484 if (gcb && gcb(current.view.token(), key, keyCode, event)) {
......
...@@ -136,12 +136,13 @@ ...@@ -136,12 +136,13 @@
136 136
137 // key bindings 137 // key bindings
138 var keyDispatch = { 138 var keyDispatch = {
139 - M: testMe, // TODO: remove (testing only) 139 + // TODO: remove these "development only" bindings
140 - S: injectStartupEvents, // TODO: remove (testing only) 140 + M: testMe,
141 - space: injectTestEvent, // TODO: remove (testing only) 141 + S: injectStartupEvents,
142 + space: injectTestEvent,
142 143
143 - B: toggleBg, 144 + B: [toggleBg, 'Toggle background image'],
144 - L: cycleLabels, 145 + L: [cycleLabels, 'Cycle Device labels'],
145 P: togglePorts, 146 P: togglePorts,
146 U: unpin, 147 U: unpin,
147 R: resetZoomPan, 148 R: resetZoomPan,
......