Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(176)

Side by Side Diff: samples/calculator/calculator.dart

Issue 10010009: Calculator App for ChromeOS with fixes for templates/CSS to support this application. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Mininimal templates and more text node tests. Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 #import('dart:html');
6 #source('tape.dart');
7 #source('settings.dart');
8 #source('calcui.dart');
9
10 var padUI; // Calculator Pad UI.
Jacob 2012/04/05 18:06:01 can this be given a type?
11
12 TapeUI tapeUI; // Tape output area UI.
13 Tape tape; // Controller.
14
15 Settings mySettings;
16
17 String currentRegister;
18 int currentOperator;
19 double total;
20
21 Set numberKeyPresses;
22 Set operatorKeyPresses;
23 Set equalKeyPresses;
24 Set clearKeyPresses;
25 Set dotKeyPresses;
26 Set backspacePresses;
27
28 void setupEvents() {
29 numberKeyPresses = new Set.from([48 /* 0 */,
Jacob 2012/04/05 18:06:01 you could make this self documenting by instead of
30 49 /* 1 */,
31 50 /* 2 */,
32 51 /* 3 */,
33 52 /* 4 */,
34 53 /* 5 */,
35 54 /* 6 */,
36 55 /* 7 */,
37 56 /* 8 */,
38 57 /* 9 */,
39 96 /* Keypad 0 */,
40 97 /* Keypad 1 */,
41 98 /* Keypad 2 */,
42 99 /* Keypad 3 */,
43 100 /* Keypad 4 */,
44 101 /* Keypad 5 */,
45 102 /* Keypad 6 */,
46 103 /* Keypad 7 */,
47 104 /* Keypad 8 */,
48 105 /* Keypad 9 */]);
49 operatorKeyPresses = new Set.from([56 /* * */,
50 187 /* + */,
51 189 /* - */,
52 191 /* / */,
53 106 /* Keypad * */,
54 107 /* Keypad + */,
55 109 /* Keypad - */,
56 111 /* Keypad / */]);
57 equalKeyPresses = new Set.from([187 /* = */,
58 13 /* ENTER */,
59 0 /* Keypad = */]);
60 clearKeyPresses = new Set.from([27 /* ESC */,
61 67 /* C */,
62 99 /* c */,
63 46 /* DEL */]);
64 dotKeyPresses = new Set.from([190 /* . */,
65 110 /* Keypad . */]);
66 backspacePresses = new Set.from([8 /* Keypad <- or Backspace */]);
67
68 addPadEvents();
69
70 // Catch user keypresses, decide whether to use them or pass to the browser.
71 document.on.keyUp.add((e) {
72 processKeyEvent(e);
73 });
74
75 document.on.click.add((MouseEvent e) {
76 // If settings dialog is open close it.
77 mySettings.close(e);
78
79 renderPad(document.body.elements.last());
80 addPadEvents();
81 });
82 }
83
84 void addPadEvents() {
85 // Hook-up number key events:
86 padUI.keyZero.on.click.add((MouseEvent e) { doCalc(48); });
87 padUI.keyOne.on.click.add((MouseEvent e) { doCalc(49); });
88 padUI.keyTwo.on.click.add((MouseEvent e) { doCalc(50); });
89 padUI.keyThree.on.click.add((MouseEvent e) { doCalc(51); });
90 padUI.keyFour.on.click.add((MouseEvent e) { doCalc(52); });
91 padUI.keyFive.on.click.add((MouseEvent e) { doCalc(53); });
92 padUI.keySix.on.click.add((MouseEvent e) { doCalc(54); });
93 padUI.keySeven.on.click.add((MouseEvent e) { doCalc(55); });
94 padUI.keyEight.on.click.add((MouseEvent e) { doCalc(56); });
95 padUI.keyNine.on.click.add((MouseEvent e) { doCalc(57); });
96 padUI.keyDot.on.click.add((MouseEvent e) { doCalc(110); });
97 // Hook-up operator events:
98 padUI.keyPlus.on.click.add((MouseEvent e) { doCalc(107); });
99 padUI.keyMinus.on.click.add((MouseEvent e) { doCalc(109); });
100 padUI.keyStar.on.click.add((MouseEvent e) { doCalc(106); });
101 padUI.keySlash.on.click.add((MouseEvent e) { doCalc(111); });
102 padUI.keyEqual.on.click.add((MouseEvent e) { doCalc(187); });
103 padUI.keyClear.on.click.add((MouseEvent e) { doCalc(27); });
104 }
105
106 void removePadEvents() {
107 // Hook-up number key events:
108 padUI.keyZero.on.click.remove((MouseEvent e) { doCalc(48); });
Jacob 2012/04/05 18:06:01 this won't remove the event listeners attached abo
109 padUI.keyOne.on.click.remove((MouseEvent e) { doCalc(49); });
110 padUI.keyTwo.on.click.remove((MouseEvent e) { doCalc(50); });
111 padUI.keyThree.on.click.remove((MouseEvent e) { doCalc(51); });
112 padUI.keyFour.on.click.remove((MouseEvent e) { doCalc(52); });
113 padUI.keyFive.on.click.remove((MouseEvent e) { doCalc(53); });
114 padUI.keySix.on.click.remove((MouseEvent e) { doCalc(54); });
115 padUI.keySeven.on.click.remove((MouseEvent e) { doCalc(55); });
116 padUI.keyEight.on.click.remove((MouseEvent e) { doCalc(56); });
117 padUI.keyNine.on.click.remove((MouseEvent e) { doCalc(57); });
118 padUI.keyDot.on.click.remove((MouseEvent e) { doCalc(110); });
119 // Hook-up operator events:
120 padUI.keyPlus.on.click.remove((MouseEvent e) { doCalc(107); });
121 padUI.keyMinus.on.click.remove((MouseEvent e) { doCalc(109); });
122 padUI.keyStar.on.click.remove((MouseEvent e) { doCalc(106); });
123 padUI.keySlash.on.click.remove((MouseEvent e) { doCalc(111); });
124 padUI.keyEqual.on.click.remove((MouseEvent e) { doCalc(187); });
125 padUI.keyClear.on.click.remove((MouseEvent e) { doCalc(27); });
126 }
127
128 void renderPad(Element parentElement) {
129 bool update = false;
130
131 if (mySettings.isSimple && !(padUI is FlatPadUI)) {
132 if (padUI != null) {
133 removePadEvents();
134 }
135 padUI = new FlatPadUI();
136 update = true;
137 } else if (mySettings.isButton && !(padUI is ButtonPadUI)) {
138 if (padUI != null) {
139 removePadEvents();
140 }
141 padUI = new ButtonPadUI();
142 update = true;
143 }
144
145 if (update) {
146 // Update calculator pad.
147
148 // Remove previous pad UI
149 if (parentElement.elements.length > 1) {
150 parentElement.elements.last().remove();
151 }
152
153 // Add new pad UI.
154 parentElement.elements.add(padUI.root);
155 }
156 }
157
158 /**
159 * Controls the logic of how to respond to keypresses and then update the
160 * UI accordingly.
161 */
162 void processKeyEvent(KeyboardEvent e) {
163 int code = e.keyCode;
164 bool shift = e.shiftKey;
165 bool ctrl = e.ctrlKey;
166
167 doCalc(code, shift, ctrl);
168 }
169
170 void doCalc(int code, [bool shift = false, bool ctrl = false]) {
171 // If settings dialog is open close it.
172 mySettings.close();
173
174 if (numberKeyPresses.contains(code)) {
175 if (code == 56 && shift) {
176 /* * operator */
177 processOperator(padUI.keyStar);
178 return;
179 } else if (code >= 96) {
180 code -= 48; // Normalize from keypad code to ASCII code.
181 }
182
183 Element element;
184 switch (code) {
185 case 48:
186 element = padUI.keyZero;
187 break;
188 case 49:
189 element = padUI.keyOne;
190 break;
191 case 50:
192 element = padUI.keyTwo;
193 break;
194 case 51:
195 element = padUI.keyThree;
196 break;
197 case 52:
198 element = padUI.keyFour;
199 break;
200 case 53:
201 element = padUI.keyFive;
202 break;
203 case 54:
204 element = padUI.keySix;
205 break;
206 case 55:
207 element = padUI.keySeven;
208 break;
209 case 56:
210 element = padUI.keyEight;
211 break;
212 case 57:
213 element = padUI.keyNine;
214 break;
215 default:
216 tape.displayError("Unknown key");
217 }
218 processNumber(code, element);
219 } else if (operatorKeyPresses.contains(code)) {
220 int op;
221
222 if ((shift && code == 56) || code == 106) {
223 /* * operator */
224 processOperator(padUI.keyStar);
225 } else if ((shift && code == 187) || code == 107) {
226 /* + operator */
227 processOperator(padUI.keyPlus);
228 } else if ((code == 189 && !shift) || code == 109) {
229 /* - operator */
230 processOperator(padUI.keyMinus);
231 } else if ((code == 191 && !shift) || code == 111) {
232 /* / operator */
233 processOperator(padUI.keySlash);
234 } else if (!shift && code == 187) {
235 // Equal operator.
236 processOperator(padUI.keyEqual);
237 } else {
238 // No match.
239 return;
240 }
241 } else if (clearKeyPresses.contains(code)) {
242 resetCalculatorState();
243 } else if (dotKeyPresses.contains(code) && !shift) {
244 processNumber(46, padUI.keyDot);
245 } else if (equalKeyPresses.contains(code) && !shift) {
246 processOperator(padUI.keyClear);
247 } else if (backspacePresses.contains(code)) {
248 if (ctrl) {
249 // CTRL + BS or CTRL + DEL works like C, c, ESC, DEL and removes all
250 // entries in the tape.
251 resetCalculatorState();
252 tape.clearTape();
253 } else {
254 currentRegister = currentRegister.substring(0,
255 Math.max(0, currentRegister.length - 1));
256 tape.addToTape(Tape.OP_NOOP, currentRegister);
257 }
258 }
259 }
260
261 void processNumber(int code, Element key) {
262 String char = new String.fromCharCodes([code]);
263
264 // TODO(terry): Need to fix this in Dart library.
265 // If there's already a . in our current register don't allow a second period.
266 // Math.parseDouble validates that 2.2.3.4.5 is okay and returns 2.2
267 if (char == '.' && currentRegister.indexOf('.') != -1) {
268 // Signal dot is valid more than once for a number.
269 flickerKey(padUI.keyDot, '-error');
270 return;
271 } else {
272 currentRegister = "${currentRegister}${char}";
273 }
274
275 flickerKey(key);
276 tape.addToTape(Tape.OP_NOOP, currentRegister);
277 }
278
279 void processOperator(var element) {
280 flickerKey(element);
281
282 if (currentRegister.length != 0) {
283 int op;
284
285 if (element == padUI.keyPlus) {
286 op = Tape.OP_PLUS;
287 } else if (element == padUI.keyMinus) {
288 if (currentRegister == "-") {
289 currentRegister = "";
290 op = Tape.OP_NOOP;
291 } else if (currentRegister == "-.") {
292 currentRegister = ".";
293 op = Tape.OP_NOOP;
294 } else {
295 op = Tape.OP_MINUS;
296 }
297 } else if (element == padUI.keyStar) {
298 op = Tape.OP_MULTI;
299 } else if (element == padUI.keySlash) {
300 op = Tape.OP_DIV;
301 } else if (element == padUI.keyEqual) {
302 op = Tape.OP_EQUAL;
303 } else if (element == padUI.keyClear) {
304 op = Tape.OP_CLEAR;
305 } else {
306 tape.displayError("Unknown operator");
307 }
308
309 // If operator has no current number then don't display another operator
310 // until operand is entered.
311 if (currentRegister.length != 0 ||
312 (tape.activeTotal == null && op == Tape.OP_EQUAL)) {
313 tape.addToTape(op, currentRegister);
314 }
315
316 currentRegister = "";
317 } else if (element == padUI.keyMinus) {
318 currentRegister = "-";
319 tape.addToTape(Tape.OP_NOOP, currentRegister);
320 }
321 }
322
323 void resetCalculatorState() {
324 flickerKey(padUI.keyClear);
325 tape.removeActiveElements();
326 if (!tape.isClear) {
327 tape.clearTotal();
328 currentRegister = "";
329 currentOperator = null;
330 total = 0.0;
331 }
332 }
333
334 void flickerKey(Element key, [String postfix = '-hover']) {
335 // Only Change classes with 1 hyphen that's the main class for an element
336 // to handle hover and active.
337 String theClass;
338 for (final String cls in key.classes) {
Jacob 2012/04/05 18:06:01 Looping through all css class names should be avoi
339 if (cls.split('-').length == 2) {
340 theClass = cls;
341 }
342 }
343 key.classes.add('${theClass}${postfix}');
344 final String nextPostfix = (postfix == '-error') ? '-error' : '-press';
345 window.setTimeout(() => resetKey(key, '${theClass}${postfix}',
346 '${theClass}${nextPostfix}'), 80);
347 }
348
349 void resetKey(Element key, String classToRemove, [String classToAdd = ""]) {
350 if (key != null) {
351 key.classes.remove(classToRemove);
352 if (classToAdd.length > 0) {
353 key.classes.add(classToAdd);
354 window.setTimeout(() => resetKey(key, classToAdd), 80);
Jacob 2012/04/05 18:06:01 make 80 a constant
355 }
356 }
357 }
358
359 void main() {
360 final Element element = new Element.tag('div');
Jacob 2012/04/05 18:06:01 nit: final Element element ==> final element; Als
361
362 // Create our Tape UI.
363 tapeUI = new TapeUI();
364 element.elements.add(tapeUI.root);
365
366 // Create our tape controller.
367 tape = new Tape();
368
369 renderPad(element);
370
371 // Render the UI.
372 document.body.elements.add(element);
373
374 currentRegister = "";
375 total = 0.0;
376
377 setupEvents();
378 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698